Versions Compared

Key

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

...

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. Each region or subvolume has its own bounding box, which is calculated in getSubVolumeBoundingBox, and the number of subvolumes is returned in getNumSubVolumes. There is also a function that returns the bounding box of the whole object, getBoundingBox. One of the optional functions, isOverlappingBoundingBox, checks the intersection of two boxes, one sent by the render engine, and the other that of the given subvolume, to optimize the rendering speed. Note that in getSubVolumeBoundingBox, getBoundingBox the returned bounding box in general is not axis-oriented, it should be subvolume-oriented, and because of this eight points must be returned. First the four "lower" ones, and then the four "upper" ones. In isOverlappingBoundingBox the input bounding box is not axis-oriented and is in the local coordinate system of the extension object, and defined by eight points. Don't underestimate the influence of this function. It can make wonders.

These extensions can also have their own custom UV generators. These generators are declared using getNumberOfUVGenerators and getUVGeneratorName. Once declared, they can be used normally with Cmaxwell::Cobject::addChannelUVW( dword uvIndex ) and Cmaxwell::Cobject::generateCustomUVW( dword iChannel, dword iGeneratorType ).The generators are implemented in getUVForChannel. This is also a speed critical function, so it must be optimized very carefully (no file I/O, no OS calls, no SDK calls...).

One of the other three functions getProxyDisplay* should be implemented if the extension writer wants to draw an approximate proxy of the object in the Studio viewport. For example, the  MaxwellGrass extension uses  getProxyDisplayLines to draw some lines representing grass strands.

 

intersect

virtual bool intersect( Cmaxwell::Cobject* object, const Cpoint& rayOrigin, const Cvector& rayDir, real time, 
const dword subVolumeIndex, Cvector* pNormal, Cvector* pLocalImpact, CfVector &data,
Cvector& parametricUVW, Cvector& tangentU, Cvector& tangentV ) = 0;

Given a ray (direction and origin), calculate and return a point and normal on the surface of the object.

Arguments

Cmaxwell::Cobject& object : input, reference to the extension object.

const Cpoint& rayOrigin : input, origin of the ray in local coordinates of the extension object.

const Cvector& rayDir : input, direction of the ray in local coordinates of the extension object.

real time : input, ranges from 0.0 to 1.0, time of the frame at which the intersection is evaluated.

const dword subVolumeIndex : input, index of the current subvolume.

Cvector* pNormal : output, return here the calculated normal direction to the surface at the intersection point, in local coordinates of the extension object.

Cvector* pLocalImpact : output, intersection point in local coordinates of the extension object.

CfVector& data : private, don't use.

Cvector& parametricUVW : output, in case of analytical surfaces, return here the natural parametric coordinates of the intersection point. Needed later to calculate texture coordinates if using custom UV generators.

Cvector& tangentU, tangentV : output, tangent vectors to the surface. If P=p(u,v), then tu = dP/du and tv = dP/dv;

Returns

true on intersection, false otherwise.

getBoundingBox

virtual void getBoundingBox( Cpoint *bboxPoints, float time ) = 0;

 

Code Block
languagecpp
titleAnalytical Sphere Example
firstline1
linenumberstrue
#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 initializeForRendering ( Cmaxwell* pMaxwell )    
    {
        pMaxwellLocal = pMaxwell;
		getExtensionData()->getDouble( "Radius", radius );
        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 )