Can the `render` function be used to speed up rendering? I am designing a moderately complicated piece in OpenScad.

It renders fast enough in preview mode (1s).
But when i do a full render so I can export to STL,
it takes ages (In the 10s of minutes)

I have read that sometimes the function render is useful to speed up overall rendering.


Is this correct, or have I misunderstood?


If I have misunderstood, what is the render function useful for?

How does this work?
In what circumstances can I apply it?
First a disclaimer: I am far from an expert on the subject, I'm just a regular Joe who happens to use OpenSCAD and have done some experimentation with it.  I believe the answer below to be correct, but I will be very grateful if errors or misconceptions were brought to my attention in the comments. :)


  I have read that sometimes the function render is useful to speed up overall rendering.  Is this correct, or have I misunderstood?


I'm unaware if it is possible to use render() to speed up the "overall rendering", but I'm rather confident that the intended purpose of render() is to simplify the in-memory representation of the model and thus the responsiveness of the preview window, rather than speed-up its final rendering.


  How does this work?


In order to understand how this work, one has to understand how Constructive Solid Geometry (CSG) works.

The entire premise of CSG is that using boolean operations between primitive solid shapes, it is possible to represent complex shapes.

However, while the human operator may see subtractive operations like difference and intersection as something that makes the model smaller in volume and thus possibly easier to handle, the computer sees each and every operation as adding geometry and complexity to the part, as the following image aptly illustrates:



When manipulating the model in the CAD viewer, OpenSCAD is in the preview mode and all that "invisible geometry" needs to be processed for each adjustment of the viewport. It is easy to reach a level at which the OpenSCAD viewer will become jittery or unresponsive.

What the render() function does, is telling OpenSCAD to compute the mesh resulting from the boolean operations enclosed in the render() call, and use that single mesh instead of the underlying boolean-combined primitives when handling the model in the viewer.  Meshes are what is normally used in the render mode of OpenSCAD (F6) rather than in the preview one, but here their advantage is not better visual quality, but the fact that OpenSCAD needs to handle a lot less geometry.


  In what circumstances can I apply it?


You can apply it any time you like, really, but it is a trade-off: a model that uses the render() function internally, will take longer to display its initial preview (because generating the mesh is an expensive operation) but it will behave very well in the viewer.  Conversely, a large model that does not leverage render() will be jittery to handle in the viewer, but it will render to screen in a fraction of the time.  It has to be noted that OpenSCAD make heavy use of caching, so the first preview is the one that will take the longest, while successive ones may be a lot faster.



For reference, the code at the bottom of this answer (which generates the image above) behaved like this:


With render(): 15s for the preview, 1m29s more for the proper rendering (TOTAL: 1m44s).
Without render(): 0s for the preview, 1m45s more for the proper rendering (TOTAL: 1m45s).


I don't know if the fact that the totals resemble each other is a coincidence peculiar to my model or a general rule of thumb (the render() function effectively creating part of the final rendering during preview), but you are free to play with the code and if you find out a pattern, please leave a comment.

In the following code, you may need to increase the grid size to 20x20 if you want to see the difference in responsiveness between vanilla code and render() function.

Also remember to close and reopen OpenSCAD between tests, in order to flush the cache.



$fn = 30;

module shape() {
    render() difference() {
        sphere();
        cylinder(r=0.3, h=3, center=true);
        rotate([90, 0, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([0, 90, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([45, 0, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([-45, 0, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([0, 45, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([0, -45, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([90, 0, 45]) cylinder(r=0.3, h=3, center=true);
        rotate([90, 0, -45]) cylinder(r=0.3, h=3, center=true);
    }
}

module line(x, y) {
    translate([x * 2, y, 0]) shape();
    if (x &gt; 0) line(x - 1, y);
}    

module grid(x, y) {
    line(x, y * 2);
    if (y &gt; 0) grid(x, y - 1);
}

grid(3, 3);