This kind of extensions implement camera lenses. This class is defined in mx_cameraextension.h.
class CcameraLensExtension : public CbaseExtension { public: virtual bool initializeForRendering( Cmaxwell::Ccamera& camera, Cmaxwell* pMaxwell ) = 0; // Returns camera origin and direction (normalized) in world coordinates, given a point in the 2D buffer (in [0,xRes],[0,yRes] range) virtual bool getCameraRay( Cpoint& origin, Cvector& direction, const Cvector2D& bufferPoint ) = 0; // Returns true if the lens has real area or false if this is an ideal lens (pinhole, spherical, etc) virtual bool hasArea( void ) const { return ( false ); } // Returns true if the lens supports Bidirectional Path Tracing virtual bool supportsBPT( void ) const { return ( false ); } // Returns by reference a 2D point in the film in [1,1] coordinates // Returns by value the PDF associated to the given input direction // If returned PDF is 0.0 the direction is not valid virtual real onLensToFilm( Cvector2D& filmPoint, const Cvector& direction ) { return ( 0.0 ); } };
The most important part of the extension functionality resides in getCameraRay, which must be implemented. The rest are optional functions. hasArea, as it name says, returns whether the lens has area or is it a pinhole kind of lens. supportsBPT tells maxwell if the lens supports bi-directional path tracing.
onLensToFilm does two things. First, returns a point in the film, and second, calculates the probability density function of the input direction. If the direction is not valid, the pdf should be 0.0.
The class extension constructor is used mainly to create the extension parameters (look at the example below) and, possibly, allocate data structures needed throughout the life of the extension. These data structures must be freed in the class destructor. initializeForRendering is called just before rendering starts, and the incoming pMaxwell (always check != NULL ) is useful for accessing the scene if needed.
getCameraRay
virtual bool getCameraRay( Cpoint& origin, Cvector& direction, const Cvector2D& bufferPoint ) = 0;
This is the main function of the extension. Given a point in the film (in [0,xRes],[0,yRes] range) returns a camera ray with its origin and direction (normalized) in world coordinates. This function is speed critical, so don´t do system calls, allocate or free memory and access files from here.
Arguments
Cpoint& origin, Cvector& direction
: output, references to the origin and direction of the ray.
const Cvector2D& bufferPoint
:input, point in the 2D buffer from which the ray will start.
Returns
true
if the ray is valid, false
otherwise.
hasArea
virtual bool hasArea( void ) const;
Returns true if the lens has real area or false if this is an ideal lens (pinhole, spherical, etc).
supportsBPT
virtual bool supportsBPT( void ) const;
Returns true if the lens supports Bidirectional Path Tracing.
onLensToFilm
virtual real onLensToFilm( Cvector2D& filmPoint, const Cvector& direction );
Returns by reference a 2D point in the film in [1,1] coordinates and by value the PDF associated to the given input direction. If the returned PDF is 0.0 the direction is not valid.
Arguments
const Cvector& direction
: input, direction for which the PDF and point in the film will be calculated.
Cvector2D& filmPoint
: output, point in the film, int range [0,1]x[0,1].
Returns
PDF of the given input direction.
class LensExtensionTest : public CcameraLensExtension { DECLARE_EXTENSION_METHODS( "Lens Test", LensExtensionTest, 1 ) public: LensExtensionTest(); ~LensExtensionTest() { cleanup( pMaxwell_ ); } bool initializeForRendering( Cmaxwell::Ccamera& camera, Cmaxwell* pMaxwell ); void cleanup( Cmaxwell* pMaxwell ){} bool getCameraRay( Cpoint& origin, Cvector& direction, const Cvector2D& onDevice ); bool hasArea( void ) const { return ( false ); } bool supportsBPT( void ) const { return ( true ); } /// DATA Cmaxwell* pMaxwell_; Cbase base_; Cpoint to_; real scaleToWindow_; }; Cbase getCameraBase( Cmaxwell::Ccamera& camera, const dword& iStep, Cbase& base, Cpoint& to ) { Cpoint from; Cvector up; real fl, fStop, stepTime; camera.getStep( iStep, from, to, up, fl, fStop, stepTime ); // Calculate base real cosAng; Cpoint focal; base.origin = from; focal.assign( to ); //to_.assign( to ); base.zAxis.substract( from, to ); // FIXED: new base real focalDistance = base.zAxis.norm(); base.zAxis.scale( 1.0 / focalDistance ); cosAng = fabs( up.dot( base.zAxis ) ); if( cosAng > 1.0 - Cnumeric::tolerance ) { up.assign( 0.0, 1.0, 0.0 ); cosAng = fabs( up.dot( base.zAxis ) ); if( cosAng > 1.0 - Cnumeric::tolerance ) { up.assign( 0.0, 0.0, 1.0 ); } } base.xAxis.cross( up, base.zAxis ); base.xAxis.normalize(); base.yAxis.cross( base.zAxis, base.xAxis ); return ( base ); } void getFilmData( Cmaxwell::Ccamera& camera, const dword& iStep, real& scaleToWindow, real& scaleToFilm ) { if( camera.isNull() ) return; Cpoint from, to; Cvector up; real fl, fStop, stepTime; camera.getStep( iStep, from, to, up, fl, fStop, stepTime ); Cvector fromToDist; fromToDist.substract( from, to ); // FIXED: new base real focalDistance = fromToDist.norm(); real focalLength = fl; //focal.length = focalLength; real radius = 0.5 * ( focalLength / fStop ); real radius2 = radius * radius; real filmDistance = fabs( ( focalLength * focalDistance ) / ( focalDistance - focalLength ) ); scaleToWindow = 1.0 - ( focalDistance + filmDistance ) / filmDistance; scaleToFilm = 1.0 - ( focalDistance + filmDistance ) / focalDistance; } LensExtensionText::LensExtensionText() { pMaxwell_ = NULL; } bool LensExtensionText::initializeForRendering( Cmaxwell::Ccamera& camera, Cmaxwell* pMaxwell ) { pMaxwell_ = pMaxwell; real scaleToFilm; base_ = getCameraBase( camera, 0, base_, to_ ); getFilmData( camera, 0, scaleToWindow_, scaleToFilm ); return ( true ); } bool LensExtensionText::getCameraRay( Cpoint& origin, Cvector& direction, const Cvector2D& filmPoint ) { // Just a simple pinhole lens test origin.assign( base_.origin ); Cvector2D scale; scale.x = filmPoint.x * scaleToWindow_; scale.y = filmPoint.y * scaleToWindow_; Cpoint onWindow; onWindow.x = to_.x + base_.xAxis.x * scale.x + base_.yAxis.x * scale.y; onWindow.y = to_.y + base_.xAxis.y * scale.x + base_.yAxis.y * scale.y; onWindow.z = to_.z + base_.xAxis.z * scale.x + base_.yAxis.z * scale.y; direction.x = onWindow.x - base_.origin.x; direction.y = onWindow.y - base_.origin.y; direction.z = onWindow.z - base_.origin.z; direction.normalize(); return ( true ); }