[OpenSCAD] Improve rendering speed

wolf wv99999 at gmail.com
Tue Jun 7 19:21:32 EDT 2016


The attached code implements another strategy to generate complex shapes. It
avoids boolean operations, and thus can speed up shape generation by a
factor of 1000-10 000 times, reducing rendering times from hours to seconds.
The code is work-in-progress, and as such is likely to contain bugs. Please
feel free to tell me. It has been developed using OpenSCAD 15.3.

The code is based upon the idea that polyhedron(vertexlist,facelist) needs
two lists to create any possible shape. The list of vertices is user
defined, and from this list the list of faces is automatically generated. 

To do so, the shape-to-be-generated is built up of a list of vertices,
called a slice, having the same z coordinate. These slices are then stacked
one on top of the other, by concatenating the lists of slices into a single
vertex list and changing the z coordinate, to generate the shape. Since
changing the z coordinate amounts to moving the slices around in space, this
is the time to change the x and y coordinates as well, implementing a
shearing action.
This is as far as the code presented goes.

Language use: implementing rotations and translations using lists of
vertices differs substantially from rotating and translating shapes. To do
so in OpenSCAD, functions have to be nested one in another, making for code
that is difficult to read and maintain. Thus, I replace rotating and
translating with tilting and moving, as an outside recognition that the
words carry the same meaning only insofar their effects on the outside (i.e.
on the eventual shape) are concerned. The inside effects (i.e. on how the
code is designed to obtain the desired results) are very different.

Tilting the slices has so far not been implemented:  Tilting the slices in
space is more demanding, since unless the tilting axes are carefully chosen,
the resulting shape will be unrecognizably distorted.

Results: To create this shape
<http://forum.openscad.org/file/n17580/Screenshot_20160608_110911.png> 
generated this output:
Rendering Polygon Mesh using CGAL...
Geometries in cache: 2
Geometry cache size in bytes: 14421616
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Total rendering time: 0 hours, 2 minutes, 7 seconds
   Top level object is a 3D object:
   Simple:        yes
   Vertices:   100200
   Halfedges:  592184
   Edges:      296092
   Halffacets: 391788
   Facets:     195894
   Volumes:         2

Doing the same shape without the centre hole generated this output:
Rendering Polygon Mesh using CGAL...
Geometries in cache: 2
Geometry cache size in bytes: 28814128
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Total rendering time: 0 hours, 0 minutes, 5 seconds
   Top level object is a 3D object:
   Facets:     200396

For both runs, the cache has been flushed beforehand.

Let me know what you think

wolf


// Reverse Slicer
// build a complex shape from user definable functions
// as a faster alternative to multiple unions


// Start user definable data
$fn=100;
Slices=1000;
SliceAngle=[for( i=[0:1:Slices-1]) [3.6*i,0,0]];         // angle by which
each slice is tilted, currently not implemented
SlicePosition=[for( i=[1:1:Slices]) [0,0,(i-1)/50]];       // position of
each slice relative to origin
SliceRadius=[for( i=[1:1:Slices]) 10/pow(i,.3)];
function CircularSlice(r=1)= // returns a list of vertices, called a slice,
centered around the origin, by which a circle of radius r and height 0 will
be approximated
                         [let(Step=360/$fn)  for( i=[0:1:$fn-1])
[r*cos(i*Step),r*sin(i*Step),0]];
// End user definable data


// Start generating list
Offset_X=flatten([for( i=[0:1:Slices-1])
MinElement_X(CircularSlice(SliceRadius[i]))]);     // list of all slices
needed to construct shape
VertexList=flatten([for( i=[0:1:Slices-1])
MoveSlice(CircularSlice(SliceRadius[i]),SlicePosition[i])]);     // list of
all slices needed to construct shape
EndFace1=[for( i=[2:1:$fn-1]) [0,i-1,i]];     // list of all triangular
faces needed to close shape at one end
EndFace2=[let(F=(Slices-1)*$fn) for( i=[F:1:F+$fn-3]) [F,i+2,i+1]];      //
list of all triangular faces needed to close shape at other end
SideFaces=flatten([for( i=[0:1:$fn-1]) for( k=[0:1:Slices])
[[i+k*$fn,(i+$fn)+k*$fn,((i+1)%$fn)+k*$fn],[((i+1)%$fn)+k*$fn,(i+$fn)+k*$fn,((i+1)%$fn+$fn)+k*$fn]]
]); 
FacesList=concat(EndFace1,SideFaces,EndFace2);

function MinElement_X(Sl,A)=  // Element of slice farthest out on negative y
axis, defines distance of tilting (rotation) axis from x axis
                         min([for( i=[0:1:$fn-1]) let (m=ExtractSlice(Sl,i))
m[1]]);                        
function flatten(l) = [ for (a = l) for (b = a) b ] ;  
function ExtractSlice(List,Element)=flatten([for( i=Element) List[i]]);   //
extract a vector from a slice
function MoveSlice(Sl,SP)=   // move slice to [x,y,z]
                         [for( i=[0:1:$fn-1]) let (v=ExtractSlice(Sl,i))
[v[0]+SP[0], v[1]+SP[1], v[2]+SP[2]]];
// end generating list
                         
// generate shape from list                       
//difference() {   // test for CSG compatibility
polyhedron(VertexList,FacesList);
//cylinder(h=1000,r=1);}







--
View this message in context: http://forum.openscad.org/Improve-rendering-speed-tp17580.html
Sent from the OpenSCAD mailing list archive at Nabble.com.




More information about the Discuss mailing list