Detailed Description
- See also:
- Class SpecialFX, Class SamplingCallback, Class
SFXParamDlg,
Class ShadeContext, Class Point3, Class Point2, Class ILoad, Class ISave.
- Description:
- This class is available in release 3.0 and later only.
This is the base class for the creation of Sampler plug-ins which work with the
Standard material. These appear in the Super Sampling rollout in
the Sampler dropdown.
They have an Enable checkbox and a Quality spinner for their user
interface. An optional modal dialog may also be presented.
A Sampler is a plug-in
that determines where inside a single pixel the shading and texture
samples are computed. For some Samplers this pattern is the same
for each pixel, for others a different pattern is chosen for each
pixel. After determining the sample locations, the sampler calls
back to the renderer to compute the shading values. It then
averages the resluting shading values and returns its estimate of
the final color.
Some Samplers are adaptive. This means that the Sampler decides on-the-fly how many
samples to take to achieve its goal. There are many subtleties to
adaptive Samplers and many ways to define the adaptive mechanism.
The adaptive mechanism used by the R3 Samplers is very simple: take
4 samples, look for the maximum change in any of the color
channels, if it's greater than the threshold, then sample the
entire pixel according to the given quality. Threshold is an
optional parameter that may, but need not be used by adaptive
Samplers.
The transfer of control from 3ds Max to the Sampler plug-in is as follows: A Sampler is responsible for the
sampling loop. It samples until it is done and computes the sum of
its samples upon completion. Once the Sampler's DoSample()
method is called 3ds Max no longer has control. This is how
adaptive samplers are handled. The DoSample() routine will
determine how often and where it samples, then it calls the
provided SamplingCallback::SampleAtOffset()
method to have 3ds Max compute the shading value.
- Plug-In Information:
- Class Defined In SAMPLER.H
Super Class ID SAMPLER_CLASS_ID
Standard File Name Extension DLH
Extra Include File Needed None
#include <samplers.h>
List of all
members.
Member Function Documentation
Receives and responds to messages.
A plugin which makes references must implement a method to
receive and respond to messages broadcast by its dependents. This
is done by implementing NotifyRefChanged(). The
plugin developer usually implements this method as a switch
statement where each case is one of the messages the plugin needs
to respond to. The Method StdNotifyRefChanged calls this, which can
change the partID to new value. If it doesn't depend on the
particular message& partID, it should return REF_DONTCARE.
- For developer that need to update a dialog box with data about
an object you reference note the following related to this method:
This method may be called many times. For instance, say you have a
dialog box that displays data about an object you reference. This
method will get called many time during the drag operations on that
object. If you updated the display every time you'd wind up with a
lot of 'flicker' in the dialog box. Rather than updating the dialog
box each time, you should just invalidate the window in response to
the NotifyRefChanged() call.
Then, as the user drags the mouse your window will still receive
paint messages. If the scene is complex the user may have to pause
(but not let up on the mouse) to allow the paint message to go
through since they have a low priority. This is the way many
windows in 3ds Max work.
- Parameters:
-
changeInt |
- This is the interval of time over which the message is
active. Currently, all plug-ins will receive FOREVER for this
interval. |
hTarget |
- This is the handle of the reference target the message was
sent by. The reference maker uses this handle to know specifically
which reference target sent the message. |
partID |
- This contains information specific to the message passed in.
Some messages don't use the partID at all. See the section List of
Reference Messages for more information about the meaning of the
partID for some common messages. |
message |
- The message parameters passed into this method is the
specific message which needs to be handled. |
- Returns:
- The return value from this method is of type RefResult. This is
usually REF_SUCCEED indicating the message was processed.
Sometimes, the return value may be REF_STOP. This return value is
used to stop the message from being propagated to the dependents of
the item.
Implements ReferenceMaker.
SClass_ID SuperClassID |
( |
|
) |
[inline, virtual] |
Retrieves a constant representing the type of the plugin.
- Returns:
- A super class id that uniquely identifies the type (category)
of the plugin. Note that several plugin classes can be of the same
type, thus return the same super class id. Plugins are uniquely
identified by their class ids. List of Super Class
IDs.
- See also:
- SClass_ID
Reimplemented from ReferenceTarget.
- Parameters:
- ISave
*isave
An interface for saving data.
Reimplemented from SpecialFX.
- Parameters:
- ILoad
*iload
An interface for loading data.
Reimplemented from SpecialFX.
- Parameters:
- ShadeOutput* pOut
This is the output of the sampling.
SamplingCallback* cb
This is the callback provided by 3ds Max which the sampler uses to
actually do the sampling.
ShadeContext* sc
The Shade Context which provides information about the pixel being
sampled.
MASK mask=NULL
The 64 bit pixel mask. This mask coresponds to the 8x8 sub-pixel
area grid. The actual geometry covers only some portion of these
bits. This is essentially an 8x8 raster for the inside of the pixel
where bits are set over the polygon being rendered and bits are off
for areas not over the polygon. Developers typically only want to
sample where the geometry is and thus when the bits are on. If not
the results are very poor visually.
Note: Most polygons are quite small in a typically complex scene
being rendered. In other words, most polygons that need to get
sampled will only have a small number of these mask bits on since
the polygons are very small relative to the pixel. For instance,
edge on polygons may project down to only a few bits within the
pixel. Consequently it is quite possible that there may be zero
samples, i.e. no geometry in the mask. Developers need to check for
this zero samples condition. If this is the case then a method of
ShadeContext called
SurfacePtScreen() is used. This method returns a point which
is guaranteed to be on the fragment no matter how small it is. This
point can then be used for at least a single sample.
- Sample Code:
- The following is a brief analysis of the DoSamples()
method from the Uniform Sampler of 3ds Max. This sampler
sub-divides the sample area into a grid and samples the pixel at
the center point of each grid unit.
This code is from the file
/MAXSDK/SAMPLES/RENDER/SAMPLERS/STDSAMPLERS.CPP.
The complete code is shown below and then a code fragment analysis
follows:
The above code is broken into smaller fragments to look at
below:
int sideSamples = GetSideSamples();
Here the sampler is just getting the number of sides in the
sampling grid. This is computed based on the Quality spinner in the
user interface. In this sampler this results in a number between 2
and 6 (developers can look at the
UniformSampler::GetSideSamples() method to see this). Thus
the resulting sampling grid is 2x2 or 3x3, up to 6x6. Then the
number of samples is computed by multiplying the number of sides
times itself.
int numSamples = sideSamples * sideSamples;
Next the side size inverse is computed to know how big the step
size is. This is the amount to step along each time.
The sample scale is how large is the piece that's being sampled.
For example, if the grid is 2x2 then each sample is scaled by
1/2
float sideSzInv = 1.0f / float(sideSamples);
float sampleScale = texSuperSampleOn ? sideSzInv : 1.0f;
Next the number of samples, and the color and transparency are
initialized to zero:
Then the sampling loop begins. Here the positions of individual
sampling points are computed. Each point is then checked to see if
it corresponds to a point in the mask (is over a polygon). (The
sampleInMask function is defined in
/MAXSDK/SAMPLES/RENDER/SAMPLERS/SAMPLERUTIL.CPP). If it is a
point that's over a polygon then SampleAtOffset() is called.
What SampleAtOffset() does is turn the passed 2D sample into
a 3D sample and fills out a ShadeOutput with a color and
transparency. These returned values are summed up over the sampling
loop ((*pOut) += sampOut;).
for( int y = 0; y < sideSamples; ++y ) {
samplePt.y = (float(y) + 0.5f) * sideSzInv;
for( int x = 0; x < sideSamples; ++x ) {
samplePt.x = (float(x) + 0.5f) * sideSzInv;
if ( sampleInMask( samplePt, mask, sc->globContext->fieldRender ) ) {
if (cb->SampleAtOffset( &sampOut, samplePt, sampleScale )) {
(*pOut) += sampOut;
nSamples += 1.0f;
}
}
}
}
At the end of the sampling loop a check is done to see if there
were zero samples. This is the case if the geometry is very small
relative to the pixel. There are two approaches that one might take
when there are zero samples. One is to simply return black. A
strict 'jitter-type' sampler might do this since, in fact, no
samples were hit. This will result in artifacts to the image
however. A better approach is to use the ShadeContext method
SurfacePtScreen() to return a point which is guaranteed to
be at the center of the fragment. Then this point is passed to
SampleAtOffset() so a single sample which is on the fragment
is used.
If a single sample point was used, DoSamples()
is finished. The reults are in pOut as returned from
SampleAtOffset().
If a number of samples was taken, the shade info is scaled by the
inverse of the number of samples (nSamples) to get the final
colors.
virtual int GetNSamples |
( |
|
) |
[pure virtual] |
virtual void SetQuality |
( |
float |
value |
) |
[pure virtual] |
- Parameters:
- float value
Quality is nominal with a range of 0.0 to 1.0.
virtual float GetQuality |
( |
|
) |
[pure virtual] |
virtual int SupportsQualityLevels |
( |
|
) |
[pure virtual] |
virtual void SetEnable |
( |
BOOL |
samplingOn |
) |
[pure virtual] |
- Parameters:
- BOOL samplingOn
TRUE for on; FALSE for off.
virtual BOOL GetEnable |
( |
|
) |
[pure virtual] |
virtual MCHAR* GetDefaultComment |
( |
|
) |
[pure virtual] |
virtual ULONG SupportsStdParams |
( |
|
) |
[inline, virtual] |
- Default Implementation:
- { return 0; }
virtual void SetTextureSuperSampleOn |
( |
BOOL |
on |
) |
[inline, virtual] |
- Parameters:
- BOOL on
TRUE for on; FALSE for off.
- Default Implementation:
- {}
virtual BOOL GetTextureSuperSampleOn |
( |
|
) |
[inline, virtual] |
- Default Implementation:
- { return FALSE; }
virtual void SetAdaptiveOn |
( |
BOOL |
on |
) |
[inline, virtual] |
- Parameters:
- BOOL on
TRUE for on; FALSE for off.
- Default Implementation:
- {}
virtual BOOL IsAdaptiveOn |
( |
|
) |
[inline, virtual] |
- Default Implementation:
- { return FALSE; }
virtual void SetAdaptiveThreshold |
( |
float |
value |
) |
[inline, virtual] |
- Parameters:
- float value
The value to set. Range 0-1.
- Default Implementation:
- {}
virtual float GetAdaptiveThreshold |
( |
|
) |
[inline, virtual] |
- Default Implementation:
- { return 0.0f; }
virtual long GetNOptionalParams |
( |
|
) |
[inline, virtual] |
- Default Implementation:
- { return 0; }
virtual MCHAR* GetOptionalParamName |
( |
long |
nParam |
) |
[inline, virtual] |
- Parameters:
- long nParam
The zero based index of the optional parameter: 0 for the first
one, 1 for the second.
- Default Implementation:
- { return _M(""); }
virtual float GetOptionalParamMax |
( |
long |
nParam |
) |
[inline, virtual] |
- Parameters:
- long nParam
The zero based index of the optional parameter: 0 for the first
one, 1 for the second.
- Default Implementation:
- { return 1.0f; }
virtual float GetOptionalParam |
( |
long |
nParam |
) |
[inline, virtual] |
- Parameters:
- long nParam
The zero based index of the optional parameter: 0 for the first
one, 1 for the second.
- Default Implementation:
- { return 0.0f; }
virtual void SetOptionalParam |
( |
long |
nParam, |
|
|
float |
val |
|
) |
|
[inline, virtual] |
- Parameters:
- long nParam
The zero based index of the optional parameter: 0 for the first
one, 1 for the second.
float val
The value to set.
- Default Implementation:
- {}
virtual void ExecuteParamDialog |
( |
HWND |
hWndParent, |
|
|
StdMat2 * |
mtl |
|
) |
|
[inline, virtual] |
- Parameters:
- HWND hWndParent
The parent window handle. Use Interface::GetMAXHWnd().
StdMat2* mtl
Points to the owning Standard material.
- Default Implementation:
- {}
- Parameters:
- EffectParamDlg* dlg
Points to the ParamDlg.
- Default Implementation:
- { return FALSE; }
Reimplemented from SpecialFX.