This type of extensions create geometry on-the-fly at render time. They are used to render objects described by mathematical expressions rather than vertices and faces. This class is defined in geometryextension.h
Code Block |
---|
class CgeometryProceduralExtension : public CbaseExtension
{
public:
virtual bool intersect( Cmaxwell::Cobject* object, const Cpoint& rayOrigin, const Cvector& dir, real time, const dword subVolumeIndex, Cvector* pNormal, Cvector* pLocalImpact, CfVector &data, Cvector& parametricUVW, Cvector& tangentU, Cvector& tangentV ) = 0;
virtual void getBoundingBox( Cpoint *bboxPoints, float time ) = 0;
virtual dword getNumSubVolumes( void )
{
return 1;
};
virtual void getSubVolumeBoundingBox( Cpoint *bboxPoints, dword subVolumeIndex, float time )
{
getBoundingBox( bboxPoints, time );
};
virtual byte getNumberOfUVGenerators( void )
{
return 0;
};
virtual const char* getUVGeneratorName( byte index )
{
return NULL;
};
virtual byte getUVForChannel( CfVector& uvw, const Cpoint& point, const Cpoint& normal, dword iGenerator, dword subVolIndex, const Cvector& parametricUVW )
{
uvw.assign( 0.f, 0.f, 0.f );
return 1;
};
virtual bool isOverlappingBoundingBox( const Cpoint *bboxPoints, dword subVolumeIndex, bool forceHalfTime )
{
return true;
};
virtual bool getProxyDisplayPoints( const dword& percent, const dword& maxPoints, dword& nPoints, float*& points )
{
return false;
};
virtual bool getProxyDisplayLines( const dword& percent, const dword& maxLines, dword& nPoints, float*& points, dword& nLines, dword*& pointsPerLine )
{
return false;
}
virtual bool getProxyDisplayFaces( const dword& percent, const dword& maxFaces, dword& nPoints, float*& points, dword& nFaces, dword*& faces )
{
return false;
}
}; |
The actual work of this extension is done in intersect. This is the speed critical routine. Make every effort to optimize this function. Do not allocate memory in it. Avoid any OS function calls in this critical routine. Most of the memory can be pre-allocated in initializeForRendering. If you want to access the global scene pointer, store it in initializeForRendering and use it later. This can save a huge amount of time.
One of the interesting things of these geometries is that they can be split into several subregions or subvolumes. This can increase the efficiency of the intersection tremendously. Instead of having an object with a huge bounding box, this can be divided into several regions, with much more smaller bounding boxes. These regions can be spatially connected or not, and each region could evaluate a different mathematical problem to calculate a point on its surface.
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
#include <math.h> #include "extensionmanager.h" #include "geometryextension.h" #include "maxwell.h" #ifndef DEG2RAD #define DEG2RAD(d) ((d) * 3.14159265358979323846 / 180.0) #endif class SphereRenderExtension : public CgeometryProceduralExtension { DECLARE_EXTENSION_METHODS( "SphereRenderExample", SphereRenderExtension, 1 ) Cmaxwell* pMaxwellLocal; double radius; public: SphereRenderExtension() { getExtensionData()->createDouble( "Radius", 1.00, 0, 1000000 ); } ~SphereRenderExtension() { } bool initialize() {initializeForRendering ( Cmaxwell* pMaxwell ) { pMaxwellLocal = pMaxwell; getExtensionData()->getDouble( "Radius", radius ); return true; } return true; } //Helper function to spit messages to maxwell. void printMessage( const char* text, const int code ) { if( pMaxwellLocal != NULL ) { char pMessage[ 1024 ]; sprintf ( pMessage, "[Extension %s] %s", getName(), text ); pMaxwellLocal->printMessage( pMessage, code ); } } dword getNumSubVolumes( void ) { return 1;//We just have one region surrounding the whole sphere }; bool intersect( Cmaxwell::Cobject* object, const Cpoint& origin, const Cvector& dir, real time, const dword subVolumeIndex, Cvector* pNormal, Cvector* pLocalImpact, CfVector &data, Cvector& parametricUVW, Cvector& tangentU, Cvector& tangentV ) { real dist, a, b, disc, t0, t1, sqr; dist = -1.0; //Assume sphere centered in ( 0, 0, 0 ) in local coordinates a = 2*( dir.x * origin.x + dir.y * origin.y + dir.z * origin.z ); b = origin.x*origin.x + origin.y*origin.y + origin.z*origin.z - radius*radius; disc = a*a - 4*b; if ( disc < 0.0 ) { return false; } sqr = sqrt ( disc ); t0 = ( -a - sqr ) * 0.5; t1 = ( -a + sqr ) * 0.5; if ( t0 <= 0.0 ) { if ( t1 > 0.0 ) { dist = t1; } else { return false; } } else { if ( t0 < t1 ) dist = t0; else dist = t1; } Cvector p; p.assign( origin + dir * dist );//Point of intersection in local coordinates pLocalImpact->assign( p ); Cvector normal; normal.assign( p ); pNormal->assign( normal );//No need to normalize. Done later on demand. return true; } void getBoundingBox( Cvector& bmin, Cvector& bmax, float time ) { bmin.assign( -radius, -radius, -radius ); bmax.assign( radius, radius, radius ); } }; EXPORT_GEOMETRY_PROCEDURAL_EXTENSION( SphereRenderExtension ) |
...