Class Texmap
See Also: Class MtlBase, Class ShadeContext, Class UVGen, Class XYZGen, Class TexHandleMaker, Class NameAccum, Class AColor, Class Matrix3, List of Procedural Texture Clamping, Noise and Misc Functions.
class Texmap: public MtlBase
Description:
This is the base class for the creation of texture map plug-ins. It provides methods for things such as calculating the color of the map for a given location, and computing a perturbation to apply to a normal for bump mapping.
Note: Developers creating procedural textures should be aware that these textures may appear less than perfect when a 3ds max user is using the "Quick Renderer" in the Materials Editor. This is not the fault of the plug-in texture, it is simply that the "Quick Renderer" uses an algorithm that is quicker but less accurate than the standard scanline renderer. Therefore, don't be concerned if your texture does not show up perfectly when using "Quick Renderer".
Plug-In Information:
Class Defined In IMTL.H
Super Class ID TEXMAP_CLASS_ID
Standard File Name Extension DLT
Extra Include Files Needed IMTL.H (and optionally TEXUTIL.H)
Method Groups:
The hyperlinks below jump to the start of groups of related methods within the class:
Texture Display in the Viewports
Get UV Transform / Texture Tiling
Additional Details related to Bump Mapping
Methods:
Prototype:
Texmap();
Remarks:
Constructor. The number of active uses of this texture is set to 0.
Prototype:
virtual AColor EvalColor(ShadeContext& sc)=0;
Remarks:
Implemented by the Plug-In.
This method is called to evaluate the color of the texture map for the context. This is for channels that have a color such as diffuse, specular, ambient, etc. This method is called for every pixel of the texture.
Parameters:
ShadeContext& sc
Describes the properties of the pixel to evaluate.
Return Value:
An AColor object which stores the r, g, b, a values. Note: The alpha is premultiplied, and the alpha value goes into AColor::a.
Prototype:
virtual float EvalMono(ShadeContext& sc);
Remarks:
Implemented by the Plug-In.
Evaluate the map for a "mono" channel. Mono channels are those that don't have a color, but rather a single value. This is for things like shininess, transparency, etc. This just permits a bit of optimization.
Parameters:
ShadeContext& sc
Describes the properties of the pixel to evaluate.
Return Value:
A floating point value for the mono channel.
Default Implementation:
{return Intens(EvalColor(sc));}
Prototype:
virtual BOOL EvalColorMonoChannel(ShadeContext& sc, int stdID, Color&
outClr);
Remarks:
This method is available in release 4.0 and later only.
This method evaluates the material on a single standard texmap channel over an area described in the ShadeContext. A return value of FALSE indicates that the value could not be evaluated.
If there's no texmap defined for a channel or the output of the texmap is not "meaningful", the raw value stored by the material or shader is returned. For the definition of the term "meaningful" see Texmap::IsOutputMeaningful().
Note that the output value is not clamped. If the method is called on a color channel, the intensity of the RGB value is returned. The intensity is computed as defined by the global helper method Interns in the 3ds max SDK.
As a default implementation, this calls EvalColorStdChannel() method and sets the result to the intensity of the color.
Parameters:
ShadeContext& sc
This describes the context in which the material should be evaluated.
int stdID
The ID of the channel to perform evaluation on. See List of Texture Map Indices **aztodo** link this
Color& outClr
The result of the evaluation.
Default Implementation:
{ return FALSE; }
Prototype:
virtual Point3 EvalNormalPerturb(ShadeContext& sc)=0;
Remarks:
Implemented by the Plug-In.
This method is used for bump mapping to retrieve a perturbation to apply to a normal.
Parameters:
ShadeContext& sc
Describes the properties of the pixel to evaluate.
Return Value:
A deflection vector for perturbing the normal.
Prototype:
virtual BOOL HandleOwnViewPerturb();
Remarks:
This method is available in release 2.0 and later only.
This query is made of maps plugged into the Reflection or Refraction slots: Normally the view vector is replaced with a reflected or refracted one before calling the map: if the plugged in map doesn't need this, it should return TRUE.
Default Implementation:
{ return FALSE; }
Prototype:
virtual void SetOutputLevel(TimeValue t, float v)
Remarks:
Implemented by the Plug-In.
Sets the output level at the specified time. It is used to set the output level of the imbedded Texout object, principally by importing plug-ins. It is implemented in all Texmaps.
Parameters:
TimeValue t
The time to set the output level.
float v
The value to set.
Default Implementation:
{}
Prototype:
void RecursInitSlotType(int sType);
Remarks:
Implemented by the System.
This method is used internally to set the slot type for all subtexmaps in a tree.
Prototype:
virtual BITMAPINFO* GetVPDisplayDIB(TimeValue t, TexHandleMaker& thmaker, Interval &valid, BOOL mono=FALSE, int forceW=0, int forceH=0);
Remarks:
This method is available in release 4.0 and later only.
This gets the viewport display bitmap in DIB format, useful when combining several maps for hardware-supported multiple texture display. If mono is TRUE, the map should do a mono evaluation and place the result in RGB. forceW and forceH, if non-zero, overide dimensions specified by thmaker.
Parameters:
TimeValue t
The time to get the bitmap at.
TexHandleMaker& thmaker
This class provides methods for creating a texture handle from a 3ds max bitmap and a Windows DIB. It also has a method to retrieve the required size of the texture map. See Class TexHandleMaker.
Interval &valid
The validity interval of the returned bitmap.
BOOL mono
Indicates whether a map should do mono evaluation.
int forceW
Overrides the bitmap width usually supplied by thmaker.
int forceH
Overrides the bitmap height usually supplied by thmaker.
Get UV Transform / Texture Tiling
Prototype:
virtual void GetUVTransform(Matrix3 &uvtrans)
Remarks:
Implemented by the Plug-In.
This method is called to retrieve the UV transformation matrix for use in the viewports. If a developer is using an instance of UVGen, a method of that class may be called to retrieve the value:
(i.e. { uvGen->GetUVTransform(uvtrans); } ).
Parameters:
Matrix3 &uvtrans
The transformation matrix is returned here.
Default Implementation:
{}
Prototype:
virtual int GetTextureTiling()
Remarks:
Implemented by the Plug-In.
This method is called to get the tiling state of the texture for use in the viewports. This is described by a set of symmetry flags that may be ORed together. If you are using an instance of UVGen to handle the UV user interface you may simply call a method of UVGen to handle this.
For example: { return uvGen->GetTextureTiling(); }
Return Value:
See List of Texture Symmetry Flags.
Default Implementation:
{ return U_WRAP|V_WRAP; }
Prototype:
virtual int GetUVWSource();
Remarks:
This method is available in release 2.0 and later only.
Returns a value indicating where to get the texture vertices for the Texmap.
Return Value:
One of the following values:
UVWSRC_EXPLICIT
Use explicit mesh texture vertices from one of the mapping channels (see GetMapChannel() below to determine which one). This uses the UVW coordinates assigned to the object, either through the Generate Mapping Coordinates option in the object’s creation parameters, or through mapping modifiers, such as UVW Map.
UVWSRC_EXPLICIT2
Use explicit mesh texture vertices from the Vertex Color Channel.
UVWSRC_OBJXYZ
Generate planar UVW mapping coordinates from the object local XYZ on-the-fly. This corresponds to the "Planar from Object XYZ" option.
UVWSRC_WORLDXYZ
This value is available in release 3.0 and later only.
Generate planar UVW mapping coordinates from the world XYZ on-the-fly. This corresponds to the "Planar From World XYZ" option. Note: this value used for the UVW is the world XYZ, taken directly, with out normalization to the objects bounding box. This differs from "Planar from Object XYZ", where the values are normalized to the object's bounding box.
Default Implementation:
{ return UVWSRC_EXPLICIT; }
Prototype:
virtual int GetMapChannel();
Remarks:
This method is available in release 3.0 and later only.
Returns the map channel being used by the texmap if GetUVWSource() returns UVWSRC_EXPLICIT. The return value should be at least 1. A value of 0 is not acceptable.
Default Implementation:
{ return 1; }
Prototype:
virtual UVGen *GetTheUVGen();
Remarks:
This method is available in release 2.0 and later only.
Texture maps that use a UVGen should implement this method to return a pointer to it.
Default Implementation:
{ return NULL; }
Prototype:
virtual XYZGen *GetTheXYZGen();
Remarks:
This method is available in release 2.0 and later only.
Texture maps that use a XYZGen should implement this method to return a pointer to it.
Default Implementation:
{ return NULL; }
Prototype:
virtual int LoadMapFiles(TimeValue t)
Remarks:
Implemented by the Plug-In.
This method is called prior to rendering to allow the plug-in to load any bitmap files it requires.
Note that LoadMapFiles() is called to load map files only, not to list the missing files. The missing files are listed using the EnumAuxFiles() method, which allows enumerating them without loading them.
Also Note: There is currently not an UnloadMapFiles() method. There are a couple of ways to do this however. One is to call Interface::FreeAllBitmaps(). That method traverses the scene reference hierarchy and calls Animatable::FreeAllBitmaps() on each item. Another approach is to evaluate the Material / TextureMap hierarchy on each material. Then call Animatable::FreeAllBitmaps() yourself in the MtlEnum::proc() shown below.
class MtlEnum {
public:
virtual void proc(MtlBase *m) = 0;
};
void EnumMtlTree(MtlBase *mb, MtlEnum &tenum) {
tenum.proc(mb);
for (int i=0; i<mb->NumSubTexmaps(); i++) {
Texmap *st = mb->GetSubTexmap(i);
if (st)
EnumMtlTree(st,tenum);
}
if (IsMtl(mb)) {
Mtl *m = (Mtl *)mb;
for (i=0; i<m->NumSubMtls(); i++) {
Mtl *sm = m->GetSubMtl(i);
if (sm)
EnumMtlTree(sm,tenum);
}
}
}
Now just define a subclass of MtlEnum that does what you want, and call EnumMtlTree. In this particular case it is more efficient than enumerating the entire reference hierarchy. If you do want to enumerate the entire reference hierarchy, here's how
class RefEnumProc {
public:
virtual void proc(ReferenceMaker *rm)=0;
};
void EnumRefs(ReferenceMaker *rm, RefEnumProc &proc) {
proc.proc(rm);
for (int i=0; i<rm->NumRefs(); i++) {
ReferenceMaker *srm = rm->GetReference(i);
if (srm) EnumRefs(srm,proc);
}
}
Just define a subclass of RefEnumProc that does what you want, and call EnumRefs on the part of the reference hierarchy you want to enumerate. For example
class MyEnum: public RefEnumProc {
void proc(ReferenceMaker *rm) { /* do something */ }
}
void afunction(Mtl* m) {
MyEnum enumer;
EnumRefs(m,&enumer);
}
Parameters:
TimeValue t
The time the maps are being loaded.
Return Value:
Always return nonzero from this method.
Default Implementation:
{ return 1; }
Prototype:
virtual void RenderBitmap(TimeValue t, Bitmap *bm, float scale3D=1.0f, BOOL filter = FALSE);
Remarks:
This method is available in release 2.0 and later only.
This method is used to render a 2D bitmap version of this texmap.
Parameters:
TimeValue t
The time at which to render the texmap to the bitmap.
Bitmap *bm
A pointer to a bitmap to render to. This bitmap must be created at the resolution you wish to render to.
float scale3D=1.0f
This is a scale factor applied to 3D Texmaps. This is the scale of the surface in 3d space that is mapped to UV. This controls how much of the texture appears in the bitmap representation.
BOOL filter = FALSE
If TRUE the bitmap is filtered. It is quite a bit slower to rescale bitmaps with filtering on.
Prototype:
virtual void InitSlotType(int sType)
Remarks:
Implemented by the Plug-In.
This method is called to initialize the slot type. This sets the proper button in the coordinate user interface rollup page. If you are using an instance of UVGen to handle the UV user interface you may simply call a method of UVGen to handle this. For example: { if (uvGen) uvGen->InitSlotType(sType); }
Parameters:
int sType
Default Implementation:
{}
Prototype:
virtual void RenderBitmap(TimeValue t, Bitmap *bm, float scale3D=1.0f, BOOL filter = FALSE);
Remarks:
This method is available in release 2.0 and later only.
Renders the texmap to the specified bitmap.
Parameters:
TimeValue t
The time at which to render the bitmap.
Bitmap *bm
The result is stored in this bitmap. The properties of this bitmap define the resolution, color depth, etc.
float scale3D=1.0f
This is the scale of the surface in 3d space that is mapped to UV.
BOOL filter = FALSE
If TRUE the bitmap is filtered. It is quite a bit slower to rescale bitmaps with filtering on.
Default Implementation:
The default implementation calls Interface::RenderTexmap().
Prototype:
virtual BOOL IsOutputMeaningful(ShadeContext& sc);
Remarks:
This method is available in release 4.0 and later only.
Implemented by the system.
Returns TRUE only if all submaps and itself have a meaningful output.
Returns FALSE if at least one sub-texmap or itself does not have a meaningful output
The output of a texmap is meaningful in a given ShadeContext if it is the same as when the scene is rendered. If the map cannot determine whether the output value is the same as when rendered, it should not be meaningful. This method can be called before EvalColor() or EvalMono() on a texmap in order to decide whether to call these methods at all or if their return values should be used in further calculations.
Parameters:
ShadeContext& sc
This describes the context of the question.
Prototype:
virtual BOOL IsLocalOutputMeaningful(ShadeContext& sc);
Remarks:
This method is available in release 4.0 and later only.
Returns TRUE if the output of this texmap is meaningful for the given context; it should not take into account subtexmaps. This method is called by IsOutputMeaningful().
Parameters:
ShadeContext& sc
This describes the context of the question.
Default Implementation:
{ return FALSE; }
Prototype:
virtual int IsHighDynamicRange( ) const;
Remarks:
This method is available in release 4.0 and later only.
Returns nonzero if the texture is returning high dynamic range data; otherwise zero.
Default Implementation:
{ return false; }
Additional Details related to Bump Mapping
Note the following information concerning bump mapping:
The following function evaluates the normal perturbation vector in the Bitmap texture.
Point3 BMTex::EvalNormalPerturb(ShadeContext& sc) {
Point3 dPdu, dPdv;
Point2 dM;
if (gbufID) sc.SetGBufferID(gbufID);
if (thebm==NULL)
return Point3(0,0,0);
uvGen->GetBumpDP(sc,dPdu,dPdv); // get bump basis vectors
if (alphaAsMono)
dM=(.01f)*uvGen->EvalDeriv(sc,&alphasamp,filterType!=FILTER_NADA);
else
dM=(.01f)*uvGen->EvalDeriv(sc,&mysamp,filterType!=FILTER_NADA);
return texout->Filter(dM.x*dPdu+dM.y*dPdv);
}
The function GetBumpDP() returns the "bump basis vectors". These are the gradient vectors of the UVW mapping in the object coordinate space.
The following function is used to compute the U and V bump basis vectors for a triangle given the texture coordinates at the three vertices of the triangle ( tv[] ) and the 3D coordinates at the vertices ( v[] ). It is simply a solution using linear algebra for the U and V axes in terms of the XYZ coordinates. It returns
b[0] = DP/DU
b[1] = DP/DV
This function does not compute DP/DW (the W bump basis vector), which at present is a shortcoming of the scanline renderer.
void ComputeBumpVectors(const Point3 tv[3], const Point3 v[3],
Point3 bvec[3]) {
float uva,uvb,uvc,uvd,uvk;
Point3 v1,v2;
uva = tv[1].x-tv[0].x;
uvb = tv[2].x-tv[0].x;
uvc = tv[1].y-tv[0].y;
uvd = tv[2].y-tv[0].y;
uvk = uvb*uvc - uva*uvd;
v1 = v[1]-v[0];
v2 = v[2]-v[0];
if (uvk!=0) {
bvec[0] = (uvc*v2-uvd*v1)/uvk;
bvec[1] = (uva*v2-uvb*v1)/uvk;
}
else {
if (uva!=0)
bvec[0] = v1/uva;
else if (uvb!=0)
bvec[0] = v2/uvb;
else
bvec[0] = Point3(0.0f,0.0f,0.0f);
if (uvc!=0)
bvec[1] = v1/uvc;
else if (uvd!=0)
bvec[1] = v2/uvd;
else
bvec[1] = Point3(0.0f,0.0f,0.0f);
}
bvec[2] = Point3(0,0,1); // TBD- How to compute this ??
}
The three Point3's returned in bvec are stored away, and then simple returned in the function SContext::GetBumpDP();
The function UVGen::EvalDeriv() evaluates the local derivative of the texture map in the U and V directions, taking into account symmetry and scaling.
The resulting derivative, dM, is scaled down from the value returned by EvalDeriv to keep the bump perturbations in a more reasonable range.
The perturbation vector is calculated as:
dM.x*dPdu+dM.y*dPdv
And then passed through the texout->Filter function, which is just the following:
Point3 Texout::Filter(Point3 c) {
if (outAmt!=1.0f) c *= outAmt;
if (flags&TEXOUT_INVERT) c = -c;
return c;
}