MAXScript Tools and Interaction with 3ds Max > Interacting with the 3ds Max User Interface > Viewports >

# Viewport Drawing Methods

The methods documented in this topic provide low-level access to 3ds Max's graphics system. These methods are available for scripts to do any graphics work not possible using the standard high-level graphics methods.

These methods are for use in the existing 3ds Max viewports, and only work on the active viewport. Note that these methods typically are not for casual use, as they are not intended to be a high level graphics library. For example, many steps are required to display a single lit polygon. These methods are optimized for speed, and not at all for script programmer ease of use.

The methods described in this topic actually operate on graphic windows. While graphic windows are not the same as viewports, they are related to one another. Each viewport has its own graphics window, and the contents of the viewport display can be thought of as a snapshot of the graphics window contents. Since writing to display memory a relatively slow operation, 3ds Max writes instead to the graphics window, and then when all the writes have been finished, it redraws the viewports with the graphics window contents.

## Viewport Drawing and the Nitrous Graphics Manager

The Nitrous Graphics Manager introduced in 3ds Max 2012 performs continuous updates to refine the final image. This requires special handling of all Graphics Methods described further in this topic. These Methods will only be executed if they are wrapped in a Scene Redraw Callback function.

In other words, existing scripts will have to be modified to check for the Nitrous Graphics Manager if running 3ds Max 2012 or higher and call all viewport drawing operations from a Scene Redraw Callback function, and newly developed scripts must take this into account and implement the same approach.

The MacroScript Macro_GrabViewport.mcr shipping with 3ds Max has been updated according to these rules and can be used as an example.

Here is another example:

EXAMPLE
The following script will display the class, name and position of every object in the scene:
    unregisterRedrawViewsCallback GW_displayObjectNames
    fn GW_displayObjectNames =
    (
      gw.setTransform (matrix3 1)
      for o in objects where not o.isHiddenInVpt do
        gw.text o.pos (o as string) color:yellow
      gw.enlargeUpdateRect #whole
    )
    registerRedrawViewsCallback GW_displayObjectNames

While the above example would also work in older versions of 3ds Max and using the Direct3D driver, this is the ONLY way to implement gw Viewport Drawing methods when using the Nitrous Graphics Manager in 3ds Max 2012.

## Graphics Driver Configuration and Support Methods

    gw.getDriverString()

This method returns a string identifying the graphics driver (and includes manufacturer info if available)

FOR EXAMPLE
on an nVidia card using MAXtreme drivers, the result would look like
    gw.getDriverString()
    "NVIDIA MAXtreme v. 6.00.07"

    gw.querySupport <feature_name>

Determines if the driver supports the specified feature. The valid <feature_name> values are:

    #txtCorrect

This is used to enable or gray-out the perspective correction right-click viewport menu option.

    #geomAccel

This is used to indicate to 3ds Max (and the mesh class in particular) that the driver wants to handle all of the 3D data natively. In this case, meshes are rendered by passing 3D world space data and letting the driver transform, clip, and light the vertices. If this returns false , then the mesh class handles all transforms, clipping and lighting calculations and then calls the hPolygon or hPolyline 2 1/2D calls for the driver to rasterize. (Primitives that are actually clipped are still sent to the polygon/polyline methods.)

Currently, only the OpenGL driver returns true to this query, but other drivers have been developed that return true , and the HEIDI and D3D drivers may change in the future.

    #triStrips

If this returns true , then 3ds Max will try to stripify meshes before calling the rendering methods. Currently, the drivers just return the user preference that is set in the driver configuration dialog. This preference defaults to true .

    #dualPlanes

If a driver has dual-planes support it returns true. The standard 3ds Max OpenGL display driver only returns true for this if the underlying display driver has implemented a custom OpenGL extension that allows 3ds Max to handle this efficiently.

    #swapModel

This returns true if 3ds Max has to redraw the whole scene any time the viewports are exposed.

    #incrUpdate

This returns true if the driver can update a rectangular subset of the viewport without trashing the image outside that rectangle. This is true for most drivers that blit the viewport region and false for those that do page-flipping in the hardware. For OpenGL, this is true if the display driver implements the Microsoft glSwapRectHintWIN extension.

    #passDecal

This is true if the driver can handle decalling with only one pass. Currently, this is true for OpenGL, but false for HEIDI and D3D.

    #driverConfig

This is true if the driver has a configuration dialog. This is true for all three of 3ds Max’s standard drivers.

    #texturedBkg

This is true if the viewport background is implemented as a textured rectangle, and false if it is a blitted bitmap.

    #virtualVpts

This is true if the driver allows viewports to be made larger than the physical window they are attached to. Currently, this is only true for OpenGL.

    #paintDoesBlit

This is true if WM_PAINT messages result in a blit of the backbuffer (as opposed to a page-flipping swap). This allows 3ds Max to do quick damage region repair, and works together with the #swapModel flag.

    #wireframeStrips

This is true if the driver wants 3ds Max to send down wireframe models using triangle strips instead of a bundle of 2-point segments. This is only used by the OpenGL driver, and it is there as a user-choosable performance-accuracy tradeoff (since the strips are faster and are back-culled, but they display hidden edges as though they are visible).

    gw.dualPlane

Gets/Sets the status of the Viewport Parameters/Use Dual Planes checkbox in the Preference Settings dialog, Viewports tab.

## Window and Viewport Transformation Methods

    gw.isPerspectiveView()

Returns true if the view is in perspective projection; otherwise false (orthographic projection).

    gw.setTransform <matrix3>

Sets the active viewport’s graphics window transformation matrix to the specified matrix3 value, and updates the modeling coordinates to normalized projection coordinates matrix. This routine also back-transforms each light and the eye point so that lighting can be done in modeling coordinates.

This method may be used to set a matrix that transforms the point passed to the drawing methods (like gw.text() , gw.marker() , gw.polyline() or gw.polygon() ). Normally these methods expect world coordinates. However if this matrix is set to an object’s transformation matrix you can pass coordinates in the object’s space coordinates and they will be transformed into world space (and then put into screen space when they are drawn). If however this is set to the identity matrix, you would pass world space coordinates. You can set this matrix to the object’s transform matrix using the following

FOR EXAMPLE
    gw.setTransform node.transform

For world-to-screen space conversions by the methods gw.text() , gw.marker() , gw.polyline() or gw.polygon() , etc, a developer must explicitly set this matrix to the identity matrix. This is because the graphics window may have a non-identity transform matrix already in place from a previous operation.

FOR EXAMPLE
    gw.setTransform (matrix3 1)

    gw.getFlipped()

Returns true if the determinant of the current transform is positive, false if negative.

## Position, Size, and Depth Clipping Methods

    gw.setPos <x_integer> <y_integer> <w_integer> <h_integer>

Sets the size and position of the graphics window. The coordinates are all Windows coordinates in the space of the graphics windows' parent window. All coordinates are in Windows format, with the origin in the upper left.

x - Specifies the left graphics window origin; y - Specifies the top graphics window origin; w - Specifies the graphics window width; h - Specifies the graphics window height.

    gw.getWinSizeX()

This method gets the current window size in X.

    gw.getWinSizeY()

This method gets the current window size in Y.

    gw.getWinDepth()

This method returns the z-buffer depth (in bits).

NoteThis method does not return the proper Z depth value in 3ds Max.

    gw.getHitherCoord()

This method returns the largest device Z value.

    gw.getYonCoord()

This method returns the smallest device Z value.

NoteThis method does not return the proper Z depth value in 3ds Max.

## DIB (Device-Independent Bitmap) Methods

    gw.getViewportDib()

This method returns the active viewport’s graphics window image as a Bitmap value. The size of the bitmap is the same size as the viewport.

See also Viewport.GetViewportDib()

## Drawing Setup

    gw.resetUpdateRect()

This method resets the update rectangle. The update rectangle is the region of the screen that needs to be updated to reflect items that have changed. When the system is done rendering items, the goal is to only update the region of the viewport that has actually been altered. This method sets the update rectangle (the region that will be blitted to the display) to a special "empty" value. This way when gw.enlargeUpdateRect() is later called, the Box2 region passed will be used as the region.

    gw.enlargeUpdateRect ( <Box2> | #whole )

This method enlarges the update rectangle to include the Box2 value passed. If #whole is specified, the whole viewport will later be updated

    gw.getUpdateRect()

This method retrieves the current update rectangle as a Box2 value. Returns a special an Box2 "empty" value if no region of the viewport needs to be updated.

    gw.setRndLimits <render_limits_name_array>

Sets the rendering limits used by primitive calls. Setting the rendering limits is used in communication between the various parts of 3ds Max that handle the display of objects. For example, setting this limit to #polyEdges and then drawing a polygon won't result in a polygon drawn with edges. It only sets a flag that indicates the edge should be drawn.

What happens is as follows. Inside the upper level 3ds Max, part of the code knows that polygon edges have been turned on. However this is not related through the object oriented architecture to the part of 3ds Max that does the actual drawing. When 3ds Max goes to draw objects it will see that the polygon edge flag is on. This tells it to do two drawing passes -- one to draw the polygon, then it calls outlinePass() call with true , draws a bunch of edges, then calls outlinePass() with false . Thus, the drawing routine is responsible for looking at the flags and drawing appropriately. This method is only responsible setting the limit which can later be checked.

<render_limits_name_array> specifies the rendering limits used by the viewport as an array of <render_limits_name> values. The valid <render_limits_name> values are:

    #allEdges

All edges of the item are shown (including hidden ones).

    #boxMode

Objects are shown using their bounding box.

    #backcull

Backface culling is used. Entities whose surface normal face away from the view direction are not drawn.

    #colorVerts

This turns on color-per-vertex display.

    #flat

Flat (facet) shading mode.

    #illum

This indicates that you have colors per vertex in your polygons and that they should be used. If you had colors per vertex but this flag was not set, the colors would be ignored.

    #lighting

This is the same as setting #illum and #specular .

    #noAtts

No attributes are specified.

    #perspCorrect

In this mode textures are corrected for perspective display.

    #pick

This indicates hit testing will be performed (not rendering).

    #polyEdges

This mode causes polygon edges (Edged Faces) to be on.

    #shadeCverts

This modifies #colorVerts . If set, lighting is enabled and the vertex colors are used to modulate the colors that result from lighting. If off, the colors on each vertex are used directly to shade the triangle. When 3ds Max uses #shadeCverts mode, it puts a white diffuse-only material on the object so that it appears that the colors are shaded without distortion.

Described further, when #shadeCverts is OFF, then the vertex colors are used directly. This is equivalent to saying that they are modulated by a pure white self-illuminated material.

When #shadeCverts is ON, the diffuse white material is illuminated by the scene lighting, resulting in shades ranging from black to white, with most vertices being some shade of pure gray. When the vertex colors are modulated by the material color, they get multiplied (in general) by a number less than 1, which makes them appear darker.

The RGB components of the colors are modulated uniformly, so that there is no shift from, say, red to green. That would happen if the underlying material was not evenly weighted (that is, a pure gray lying between black and white). Said another way, only the intensity of the vertex colors is changed when shading is on, not luminance, chrominance, etc.

    #specular

This enables specular highlight display.

    #texture

This enables texture display.

    #twoSided

Faces are displayed regardless of their surface normal orientation.

    #vertTicks

This mode is really a pseudo-mode, in that it doesn't actually cause the graphics drivers to do anything differently, but rather is tested by the Mesh class, which sends down vertex markers (+) if the mode is on.

    #wireframe

Wireframe rendering mode.

    #zBuffer

When coordinates are specified for drawing primitives they have x, y, and z values. Sometimes when drawing entities in the viewports it is desirable to ignore the z values. For example in the 3ds Max viewports the text that display the type of viewport (Front, Left, and so on) are drawn without z values. So are the arc-rotate circle control and the axis tripods. These items are drawn without this flag being set so they always show up in front.

    gw.getRndLimits()

Retrieves the rendering limits used by primitive calls as an array of names. See gw.setRndLimits() for a list of the returned name values.

    gw.getRndMode()

Returns the current rendering mode used by the viewport as an array of names. This is a subset of the rendering limit, in that any limits imposed by the rendering limit are forced onto the current mode. See gw.setRndLimits() for a list of the returned name values.

    gw.setSkipCount <skip_count_integer>

Sets the number of triangles skipped when the viewport is set as a 'Fast View Display' viewport. To disable fastview, specify 1. Since triangles are handed down to graphics driver one at a time, it is up to the code that feeds triangles to the graphics driver to skip the specified number of triangles. The mesh rendering in 3ds Max uses the skip count in this way.

<skip_count_integer> specifies that every 'n-th' triangle should be drawn. If set to 2, every other triangle should be drawn.

    gw.getSkipCount()

Returns the current skip count setting.

The following is an example of using the above functions
     -- Get the current rendering limits
    lim = gw.getRndLimits()
    -- Add another limit
    append lim #polyEdges
    -- Set the new rendering limits
    gw.setRndLimits lim
    -- Get back the rendering limits to check
    gw.getRndLimits()
    -- Get back the rendering mode to check
    gw.getRndMode()

    gw.setDirectXDisplayAllTriangle <bool>

Exposes the Display All Triangle Edges option available in the UI as a checkbox in the Customize>Preferences>Viewports>Configure Driver dialog of the Direct3D driver. When set to true, all edges will be drawn. When set to false, only visible edges will be drawn.

Available in 3ds Max 9 and higher.

## Light and Camera Methods

    gw.getMaxLights()

Returns the maximum number of lights that may be used by the interactive renderer.

## Coordinate Transformation Methods

The following methods map points from the graphic window's current transform to device space. If the graphic window's transform is set to the identity matrix then the mapping is done from points specified in world space. Otherwise the points given are transformed by the graphic window’s transform, and are then considered to be in world space. Thus, o get a world-space to screen-space conversion, you need to set the graphic window’s transform to the identity with

CODE:
    gw.setTransform(Matrix3 1)

    gw.hTransPoint <point3>

This method converts the point3 coordinate to a "h" format device coordinate. Each component of the return value is in integer format in the native device coordinates for the graphics driver. For HEIDI and OpenGL, the origin is at the lower left. For Direct3D the origin is at the upper left.

    gw.wTransPoint <point3>

This method converts the point3 coordinate to a "w" format device coordinate. Each component of the return value is in integer format with the origin at the upper left.

    gw.transPoint <point3>

This method converts the point3 coordinate to a "h" floating point coordinate. Each component of the return value is in float format with the origin at the upper left. This is just a helper routine to avoid building up round-off error. 3ds Max uses it just for IK.

## Drawing Methods

Methods that start with "h" take integer device coordinates with the origin at the lower-left. Methods that start with "w" in front take Windows device coordinates with the origin at the upper left. These "h" and "w" routines perform NO clipping unless otherwise noted. Drawing outside the allowable region is likely to cause 3ds Max to crash. These coordinate systems are left-handed.

Methods that don’t start with "h" or "w" map points from the graphic window's current transform to device space. This coordinate system is right-handed. If the graphic window's transform is set to the identity matrix then the mapping is done from points specified in world space. Otherwise the points given are transformed by the graphic window’s transform, and are then considered to be in world space. Thus, to get a world-space to screen-space conversion, you need to set the graphic window’s transform to the identity with:

CODE:
    gw.setTransform(Matrix3 1)

After completing any drawing to the graphics window with the methods described in this section, you need to call gw.updateScreen() to update the viewport display.

    gw.updateScreen()

Updates the viewport display to display any text, markers, polylines, polygons, or tristrips written to the graphics window via the methods described below.

    gw.text <point3> <string> [ color:<color> ]
    gw.hText <point3> <string> [ color:<color> ]
    gw.wText <point3> <string> [ color:<color> ]

Draws 2D fixed font annotation string text to the specified location using the specified (optional) color. If the color is not specified, a default color of red is used.

Note

This routine DOES perform clipping of the text if it is off the screen.

    gw.getTextExtent < string >

Returns the text extents of the string as it would be displayed in the viewports as a point2 value.

    gw.Marker <point3> <marker_name> [ color:<color> ]
    gw.hMarker <point3> <marker_name> [ color:<color> ]
    gw.wMarker <point3> <marker_name> [ color:<color> ]

Draws a marker at the specified location. This is can be paired with pickpoint() to quickly show where the user has clicked. These markers are temporary and will be erased whenever the viewports are updated. If the color is not specified, a default color of red is used. The valid <marker_name> types are:

    #point #hollowBox #plusSign #asterisk #xMarker #bigBox #circle #triangle #diamond #smallHollowBox #smallCircle #smallTriangle #smallDiamond

The following is an example that creates an instance of all types of markers, spaced equally:

EXAMPLE:
    arr = #("point","hollowBox","plusSign","asterisk","xMarker",
    "bigBox","circle","triangle","diamond","smallHollowBox",
    "smallCircle","smallTriangle","smallDiamond")
    for i=1 to arr.count do (
    gw.hMarker [100, (50 + i*10), 50](arr[i] as name) )
    gw.enlargeUpdateRect #whole
    gw.updateScreen()

    gw.Polyline <vertex_point3_array> <isClosed_boolean> [rgb:<color_array>]
    gw.hPolyline <vertex_point3_array> <isClosed_boolean> [rgb:<color_array>]
    gw.wPolyline <vertex_point3_array> <isClosed_boolean> [rgb:<color_array>]

This method draws a multi-segment polyline. Each value in <vertex_point3_array> is a vertex on the polyline. If <isClosed_boolean> is true , the first point is connected to the last point, that is, the polyline is closed. If false , the polyline is left open. If the optional rgb color array is specified, and shade mode is set to smooth, the polyline will be drawn Gourand shaded. This is how 3ds Max draws lit wireframes for instance. If the optional rgb color array is not specified, the line is drawn with the line color specified via gw.setColor() . The number of elements in <color_array> must be the same as in <vertex_point3_array> .

    gw.Polygon <vertex_point3_array> <color_array> <uvw_point3_array>
    gw.hPolygon <vertex_point3_array> <color_array> <uvw_point3_array>
    gw.wPolygon <vertex_point3_array> <color_array> <uvw_point3_array>

This method draws a multi-point polygon. Each value in <vertex_point3_array> is a vertex on the polygon. <color_array> specifies the color at each vertex. The rendering mode (set via gw.setRndLimits() ) must include #illum for the color values to be used. <uvw_point3_array> specifies the UVW coordinates at each. The rendering mode must include #texture for the UVW coordinates to be used. The number of elements in each array must be identical.

    gw.hRect <box2> <color>
    gw.wRect <box2> <color>

Draws a rectangle in the given color using the coordinates specified by box2.

Available in 3ds Max 2008 and higher. reviously available in Avguard Extensions.

EXAMPLE:
    rect = (box2 13 47 96 97)
    gw.wrect rect red
    gw.wmarker [rect.left,rect.top,0] #point color:green
    gw.wmarker [rect.left,rect.bottom,0] #point color:green
    gw.wmarker [rect.right,rect.top,0] #point color:green
    gw.wmarker [rect.right,rect.bottom,0] #point color:green
    eRect = rect -- enlargeUpdateRect 1 pixel too small in either direction?
    eRect.right += 1
    eRect.bottom += 1
    gw.enlargeUpdateRect eRect
    gw.updateScreen()

    gw.startTriangles()

This method is called to begin sending a series of triangles to render. Call this method, then gw.triangle() one or more times, then gw.endTriangles() to finish.

Available in 3ds Max 2008 and higher. Previously available in Avguard Extensions.

    gw.endTriangles()

Call this method to finish rendering triangles.

Available in 3ds Max 2008 and higher. reviously available in Avguard Extensions.

    gw.triangle <vertex_point3_array> <color_array>

This method draws a triangle. Each value in <vertex_point3_array> is a vertex on the triangle.

<color_array> specifies the color at each vertex. The rendering mode set via gw.setRndLimits() must include #illum for the color values to be used.

There must be 3 elements in each array.

Call gw.startTriangles() first, call gw.triangle() one or more times, then gw.endTriangles() when done drawing triangles.

Available in 3ds Max 2008 and higher. reviously available in Avguard Extensions.

EXAMPLE:
    gw.setTransform(Matrix3 1)
    gw.startTriangles()
    gw.triangle #([0,0,0], [50,0,0], [50,50,0]) #(red,red,red)
    gw.triangle #([0,0,0], [50,50,0], [0,50,0]) #(green,green,green)
    gw.endTriangles()
    gw.enlargeUpdateRect #whole
    gw.updateScreen()

    gw.triStrip<vertex_point3_array> <color_array> <uvw_point3_array>

This method is used for drawing a series of triangles specified as 'strips'.

The method takes 3 or more vertices and builds triangles in a strip. This sends a lot less data and the underlying graphics library has to set up a lot less data since it can use the previous information to start the rasterization, resulting in a significant speed increase. This routine does no clipping so all the vertices passed must be within view.

The parameters are the same as for the gw.Polygon() . However, the <vertex_point3_array> is handled differently. After the first two vertices, each new vertex is used to create a new triangle. For instance, to draw a quad, the first three vertices specify the first triangle and the next one is combined with the previous two to complete the square.

Available in 3ds Max 2008 and higher. Previously available in Avguard Extensions.

    gw.hTriStrip <vertex_point3_array> <color_array> <uvw_point3_array> gw.wTriStrip <vertex_point3_array> <color_array> <uvw_point3_array>

Note

These two methods are currently broken. Please use the gw.triStrip and Polygon methods above.

The following is an example of using the above functions:

EXAMPLE:
     -- Draw some primitives
    gw.hPolyline #([300,50,16], [300,200,8], [450,250,4]) true
    --
    gw.hPolygon #([200,100,16], [280,100,8], [250,200,4]) \
    #(red, blue, green) \
    #([1.0,.5,0], [0.5,0.5,0], [0,0,0.5])
    -- Update the viewports
    gw.enlargeUpdateRect #whole
    gw.updateScreen()

    gw.setColor <type_name> <color_value>

Sets the RGB color used for the specified drawing type. The valid <type_name> values are:

    #line -- line drawing color  #fill -- polygon fill color  #text -- text drawing color  #clear -- The color that the viewport is cleared to when you call gw.clearScreen()

    gw.clearScreen <Box2> [ useBkg:<boolean> ]

Clears the specified rectangular region of the screen. If the optional useBkg parameter is set to false , the region is set to the "clear" color (see gw.setColor() above). If true , the background should be used to fill the cleared area. The default useBkg value is false .