Jump to content

User:VulcanWikiEdit/OpenSCAD User Manual/Rendering

From Wikibooks, open books for an open world

Rendering Issues

[edit | edit source]

Every application that provides 3D modelling, rendering, and animation has to select the technologies to adapt to its purposes. This section is presenting the issues that the choices made for OpenSCAD bring to the user, and discuss how to take advantage of them while mitigating their weaknesses.

A Quick Sketch of Preview Rendering

[edit | edit source]

The preview render works by presuming an eye point looking towards the objects in view, dividing up the viewport into pixels, and reviewing every shape as to the pixels it will be drawn in.

The math definition of each curved shape is combined with the smoothness parameters to calculate how to sub-divide curves into lines (2D) or polygons (3D). Preview makes a list of the polygons that face the eye point and then, using the geometry of each polygon and the position of the eye point, projects the polygon onto the viewport to calculate which pixels the polygon is visible in. If the part of the polygon in a particular pixel is closer to the eye than any previously considered a color value is calculated and replaces the value for the given pixel.

This process is called Z-Buffering where the "Z" is the distance in a projection space from the eye point to a point on a surface in the view.

Parameters That Affect Rendering

[edit | edit source]

Convexity

[edit | edit source]

Convexity is a parameter for a number of Object Modules. It is an integer with a default of one (1) that works as a measure of complexity based on the maximum number of sides a viewer might see looking at a shape.

The preview rendering mode uses convexity to be sure that it "paints" each pixel correctly for each shape. The full rendering operation uses a different method that ignores convexity.

There is fuller explanation on the OpenCSG site in the Usage section.

The preview render "looks" at each shape through the pixels of the viewport to know what to paint. When the object is simple, showing a single surface to the eye point, it only needs to check the surface once for each pixel.

For instance, the convexity of a sphere needs only to be one (1) as only one surface can be seen from any view point. But a shape with folds, holes, and bumps will have a variable number of surfaces when viewed from different points around it. From some positions a torus will present one surface, but looking at it edge on the near part covers the far side of the hole, thus the render needs to always check for two surfaces in each pixel, and convexity must be 2.

In general the convexity value must be as large as the maximum number of surface crossings that may be seen viewing from the "worst case position".

This 2D shape has a convexity of 2, as there is at least one ray (the red line) that passes through its boundary twice. If convexity was at the default 1 the rendering process would stop at the first intersection, possibly missing second part of the curve.

Note:
Arbitrarily setting convexity to a high value may solve some preview rendering issues, at the expense of slowing preview rendering, possibly even causing the app to lock up.


Curve Smoothness: $fa, $fs, and $fn

[edit | edit source]

These are three of the Special Variables defined as part of the language.

Best Practice: Set $fs=0.5, $fa=1, $fn=0 for good smooth curves with reasonable performance and only use $fn > 0 to generate regular polygons.

The $fa, $fs values, OR the $fn value, are used to calculate how many facets a curved line or surface should be divided into, creating line segments or polygons respectively, to approximate a smoothed curve.

Smoothness Notes

  • The terms fragment and facet are used interchangeably in this section.
  • When $fn > 0, $fs and $fa are not used, and vice versa
  • the number of facets is always an integer value.

Not Really About Rendering

[edit | edit source]

These smoothness variables are actually involved in the generation of geometry, not rendering per se. Of course the generation of polygonal approximations of the mathematical shapes modeled by a script is pretty close to the rendering process. Just without rendering an image or exporting an STL file to be 3D printed.

Including this section in the Rendering page is a reflection of it being a source of rendering issues.

Using $fa and $fs

[edit | edit source]
a circle divided in the default 5 segments
a circle divided in the default 5 segments

When $fa and $fs variables are being used curved objects are divided into a minimum of 5 fragments.

$fa is the minimum angle for a fragment, the angle A-B-C in the diagram, and controls the division of large circles. The minimum angle prevents a large circle being divided into microscopic facets that can't be rendered or a reproduced on a 3D printer. The default value is 12 which gives 30 fragments around a circle. The minimum value allowed is 0.01.

$fs is the minimum size of a fragment, measured in millimeters along its arc length, from A to C (in red) and controls the division of small circles. The minimum arc length prevents a circle being divided into microscopic sides, as for $fa. The default value is 2 so very small circles have a smaller number of fragments than specified using $fa. The minimum allowed value is 0.01.

The radius of curvature is factored into the fragments calculation so best practice recommendation of $fa=1 and $fs=0.5 produces smooth looking curves for a very wide range of size.

Using $fn

[edit | edit source]

When greater than zero, $fn is an integer value setting the number of fragments that a curved line or surface will be divided into, to a minimum of 3. When assigned a floating point value any fractional part is truncated, thus $fn=6.89 results in 6-sided objects.

Curves will appear to be smoother as $fn is increased, but will require more memory and CPU power to render. Setting $fn >= 128 is not recommended.

Best Practice: is to only use $fn to create regular polygonal shapes, leaving curve smoothness to $fa and $fs. low values for $fn may be used to create regular polygons or 3D prisms

When the $fn value is divisible by 4 the polygon will be drawn on integral boundaries and be inscribed within a circle of the given diameter.

Slicing Solids

[edit | edit source]

The curved 3D objects, spheres and cylinders, are divided into pie-shaped facets in the same way as circles are, and are also divided into horizontal "slices" using a similar calculation. Then, between the vertices formed by the divisions four sided polygons are drawn. The tops and bottoms are drawn as polygons with the same number of edges as there are facets.

This subdivision method is used on curved, regular shapes imported from DXF files, but is not used on 3D shapes from STL files as they are already in triangles.

Calculating Number of Fragments

[edit | edit source]

This is the C code that calculates the number of fragments for a circle of radius "r":

 int get_fragments_from_r(double r, double fn, double fs, double fa)
     {
     if (r < GRID_FINE)
         return 3;
     if (fn > 0.0)
         return (int)(fn >= 3 ? floor(fn) : 3); // minimum 3
                  // which ever of $fa or $fs is used, minimum 5
     return (int) ceil( fmax( fmin( 360.0 / fa, r*2*M_PI / fs), 5 ) );
     }

GRID_FINE is an arbitrary constant for the smallest radius that will be accepted as an argument to the primitive generating object modules.

This is the equivalent calculation in OpenSCAD given a radius (r) for the curve:

 r=10; // radius of the curve being considered
 echo(
   n=($fn>0?
       ($fn>=3? $fn : 3) : 
       ceil( max( min( 360/$fa, r*2*PI/$fs ), 5 ) )
       ),
   a_based = 360/$fa,
   s_based = r*2*PI/$fs
   );
 ECHO: n = 30, a_based = 30, s_based = 31.4159

The curvature variables may be set globally in a program:

$fs = 3.1;
sphere(2);

or individually set on a primitive as a named parameter:

sphere(2, $fn = 6.4);

or modified by a scaling factor taking advantage of local scope rules:

sphere( 2, $fa = $fa*1.1 );

Viewport: $vpr, $vpt, $vpf and $vpd

[edit | edit source]

These Special Variables reflect the current viewport parameters at the time of rendering.

The current viewport values may be copied onto the clipboard using the menu items Edit > Copy Viewport *. From there it may be pasted into a script.

Changing the view interactively does not affect the special variables. During an animation they are updated for each frame.

$vpr
rotation vector of floats [phi-x,phi-y,phi-z] - Camera Pan, Tilt & Yaw
$vpt
translation vector [x,y,z] - Camera Rack, Truck & Pedestal
$vpf
non-negative float > 5, - Camera Zoom, set as the angle in degrees of the Field of View (FoV) [Note: Requires version 2021.01]
$vpd
non-negative float > 0.01, the camera distance [Note: Requires version 2015.03]

These four variables give the position and orientation of the camera, or eye point, that is used as the basis for rendering images.

Rotation Vector

[edit | edit source]

The effect of rotation on the camera must always factor in the cameras base position and its distance.

With rotation set to [0,0,0] and translate=[0,0,0] the view is down the Z axis to the origin. The camera's rotation is clockwise, considered looking from the origin in the positive direction of the axis, so [0,90,0] rotates the camera "down" to the X axis, still looking at the origin.

Rotations are applied at the translated position of the camera and will appear to be reversed by the change in the viewport. Rotating to move the view up means applying a rotation to tilt the camera down. Likewise, to look left the camera must rotate to the right. The effect of rotation is magnified when the Camera Distance is larger.

Translation Vector

[edit | edit source]

This sets the base position of the camera in coordinate space and is not affected by rotate and zoom. We say the base position as the camera is actually positioned the camera distance along the direction of the rotation vector from its base position.

Field of View

[edit | edit source]

This is the angle, in degrees, of the viewing area of the camera. Making the FoV larger does Zoom In, and smaller values Out.

Camera Distance

[edit | edit source]

A floating point value for the distance, in millimeters, from the base position to the camera, along the vector set by the rotation vector.

Example

$vpr = [0, 0, $t * 360];

causes the camera to rotate 360 degree the Z axis when animating.

Render Mode: $preview

[edit | edit source]

[Note: Requires version 2019.05]

This Special Variable may be interrogated to know in which rendering mode the script is being run.

When in OpenCSG preview mode (F5) $preview is true. Doing a render (F6) it is false.

Tip: $fn should not be used to globally control how curved shapes are sub-divided, $fa & $fs do a better job

The render() module operates differently from either rendering mode. The value of $preview is undetermined in this snippet:

render(){
    $fn = $preview ? 12 : 72;
    sphere(r = 1);
}

The tessellation result is the same regardless.

Command Line Operation

When using the command line to render $preview is only true when exporting a PNG image. For all other forms of output ( STL, DXF, SVG, CSG, and ECHO files ) it is false. It can be forced true using the -D command line option.

Examples

$preview can be used to model in reduced detail but have fully smoothed curved surfaces the final rendered result:

FNspecial = $preview ? 12 : 72;
sphere(r = 1, $fn=FNspecial );

Best Practice: The $fn argument to the module is used so that no other shapes are affected.

Another use could be to show a complex part assembled during preview but spread out and positioned for 3D printing during rendering.

OR: When horizontal features require support in 3D printing the object may be previewed without the support structures, but rendered with them, then exported to STL for printing.

Render Module

[edit | edit source]

This module may be used to force tessellation for all shapes. Its use is described in the Syntactic Modules section