// Object-slicing code for 3-D printing. The resulting rendered images are specifically for // subsequent use in the 3D SLICER app-- // https://www.slicer.org/ // // Kenneth Walker 12/30/23 ---> 4/2/24 //----------------------- #version 3.7; // or 3.8 global_settings{assumed_gamma 1.0} #declare DFLT_TXTR_ = texture {finish{ambient 1 emission 0 diffuse 0}} #declare INITIAL_LINEUP_= on; // [TURN OFF FOR THE ACTUAL ANIMATED SLICING!] /* The following six *optional* 'adjusters' are for the INITIAL_LINEUP_ step. IMPORTANT NOTE: AFTER adjusting any/all SIX of these, you need to look again in the 'Messages' pane for the slightly NEW slicing settings that have been created. [These FOUR variable names relate to the on-screen appearance of this initial render, and do not correspond to the actual spatial axes or real orientation of the object. The slicing camera is looking up from below, and some of the x-y-z directions are reversed in the image.] */ #declare LINEUP_ADJUST_LEFT_SIDE_ = 0.0; // +/-, for adjusting the red boundary on the left side #declare LINEUP_ADJUST_RIGHT_SIDE_ = 0.0; // +/-, ditto, for the right side #declare LINEUP_ADJUST_TOP_ = 0.0; // +/-, for adjusting the red boundary at the top #declare LINEUP_ADJUST_BOTTOM_ = 0.0; // +/-, ditto, for the bottom /* For these two optional adjustments, turn *off* INITIAL_LINEUP_. These are for tweaking the actual animation-- to adjust 'when the model appears' in the first and last frames. */ #declare BB_ADJUST_BOTTOM_ = 0.0; // +/-, for bounding_box size-- the y-volume. This is where the first // slice begins-- where the camera begins 'seeing' the object. #declare BB_ADJUST_TOP_ = 0.0; // +/-, ditto; this is where the last slice ends. #declare MY_VOXEL_LIMIT_ = 950000000; /* in 3D SLICER (as relates to my own computer's power). Depending on your machine, you may need to adjust this up or down. Actually, the value entered here is (typically) far more voxels than is actually created in 3D SLICER-- depending on the object. (NOTE that this value interacts with 'L_ADJUST_' below, regarding the 'messages' that are returned: If you decrease the limit here, L_ADJUST_ needs to decrease as well-- only to get consistent message behavior. It is not critical.) */ #declare L_ADJUST_ = 35; // an empirical value #declare USE_CUTAWAY_TEXTURES_ = off; #declare SLICE_OBJ_ = // ...your object or CSG goes here (in-line or as an #include file), // to be re-#declared as SLICE_OBJ_ // TEMPORARY TEST OBJECT... union{ // overall difference{ union{ sphere{0,1 scale 1} cylinder{-1*y,.5*y, .6} } sphere{0,.7 translate <0,0,-1.2>} } union{ text { ttf "timrom.ttf" "P" .7, 0 scale .7 translate <-.105,1.015,0> rotate 58*z } text { ttf "timrom.ttf" "O" .7, 0 scale .7 translate <-.235,1.04,0> rotate 34*z } text { ttf "timrom.ttf" "V" .7, 0 scale .7 translate <-.27,1.03,0> rotate 13*z } scale <1,1,.7> translate <0,-.06,-.17> rotate -35*z texture{pigment{rgb .7*<0,1,.7>} finish{ambient .05 emission 0 diffuse .9}} } union{ text { ttf "timrom.ttf" "r" .3, 0 translate <-.2,-.24,-.2> scale .7 // translate <-.09,0,0> rotate 90*x translate .75*y rotate 20*z } text { ttf "timrom.ttf" "a" .3, 0 translate <-.2,-.24,-.2> scale .7 rotate 90*x translate .75*y } text { ttf "timrom.ttf" "y" .3, 0 translate <-.26,-.16,-.2> scale .7 rotate 90*x translate .75*y rotate -3.3*x rotate -20*z } scale 1.25 rotate -30*x texture{pigment{rgb .7*<0,1,.7>} finish{ambient .05 emission 0 diffuse .9}} } union{ sphere{0,0.5} difference{ cylinder{-1*y,1*y,.25} box{0,1 translate <-.5,0,-.5> scale <.15,.3,.7> rotate 45*y translate .75*y} box{0,1 translate <-.5,0,-.5> scale <.15,.3,.7> rotate -45*y translate .75*y} } translate 2*x } difference{ union{ box{0,2 translate -1 } box{0,2 translate -1 scale <.8,1,.8> translate .2*y} } cylinder{-1.1*y, 1.25*y,.6} translate -2.7*x } cylinder{<0,0,-.15>,<0,0,.15>,.4 translate <-1.65,-.1,0>} box{0,2 translate <-1,0,-1> scale <.1,.8,.4> rotate -45*z translate <-1.9,-.81,0>} box{0,.25 translate -.25/2*z scale <8,1,1> translate <0,-1,0>} cone{0,.9,-1.3*z,0 translate <-2.7,0,-.9>} texture{ pigment{ gradient x scale .7 color_map{ [.5 rgb <1,.7,.2>] [.5 rgb .9*<0,.2,1>] } translate -.2*x } finish{ambient .05 emission 0 diffuse .95 phong .6 phong_size 18} } // for testing scale 37 translate -54 } // end of test object //------------------ // This is required because of the difference in the *default* object-color // between v3.7.0 (black) and 3.8 (white): #declare SLICE_OBJ_COLOR_ = rgb 1; background{rgb 0} #if(frame_number !=0) #debug concat("\n\n", "frame_number = ",str(frame_number,0,0),"\n") #else #end //---------------- // SLICING preliminaries-- #declare MIN_BB_ = min_extent(SLICE_OBJ_) + LINEUP_ADJUST_LEFT_SIDE_*x + BB_ADJUST_BOTTOM_*y - LINEUP_ADJUST_TOP_*z; #declare MAX_BB_ = max_extent(SLICE_OBJ_) + LINEUP_ADJUST_RIGHT_SIDE_*x + BB_ADJUST_TOP_*y - LINEUP_ADJUST_BOTTOM_*z; #declare XYZ_SIZE_ = MAX_BB_ - MIN_BB_; #if(frame_number !=0 & INITIAL_LINEUP_) #debug concat("\n\n","----- You forgot to turn off INITIAL_LINEUP_ !! -----","\n\n\n") #else #debug concat("\n","object size using min_extent and max_extent:","\n","<",vstr(3,MIN_BB_,", ",0,4),">",","," <",vstr(3,MAX_BB_,", ",0,4),">","\n") /* ----------- to temporarily re-scale an object that is either too large or too small; because objects need to be in a certain size range to report the necessary info to the messages pane, in a 'consistent' way. This size change is not used for the actual slicing. */ #declare VOL_ = XYZ_SIZE_.x * XYZ_SIZE_.y * XYZ_SIZE_.z; #debug concat("\n", "X-Y-Z VOLUME (actual) = ",str(VOL_,0,4),"\n") #declare BAR_ = L_ADJUST_/VOL_; //#debug concat("resulting BAR multiplier = ",str(BAR,0,4),"\n") #declare XYZ_SIZE_ = XYZ_SIZE_*pow(BAR_,1/3); #debug concat("\n","NEW TEMP X-Y-Z volume = ","<",vstr(3,XYZ_SIZE_,", ",0,4),">"," = ",str(XYZ_SIZE_.x*XYZ_SIZE_.y*XYZ_SIZE_.z,0,4),"\n") #debug concat("\n"," RENDER WIDTH multiplier = ",str(XYZ_SIZE_.x,0,3),"\n") #debug concat(" RENDER HEIGHT multiplier = ",str(XYZ_SIZE_.z,0,3),"\n") // yes z, because slices are horizontal #debug concat(" NUMBER OF SLICES (animation frames) multiplier = ",str(XYZ_SIZE_.y,0,3),"\n") //-------------------- #macro EXCESS(_L_,XYZ_SIZE_) #debug concat("for command line: +w",str(_L_*XYZ_SIZE_.x,0,0)," +h",str(_L_*XYZ_SIZE_.z,0,0)," +kff",str(_L_*XYZ_SIZE_.y,0,0)," +fng +q0","\n") #if(_L_*XYZ_SIZE_.x * _L_*XYZ_SIZE_.y * _L_*XYZ_SIZE_.z > MY_VOXEL_LIMIT_) // my computer's voxel limit when using 3D SLICER (especially its 3-D view) #debug concat( " ***possibly TOO MANY VOXELS***","\n\n") #else #end #end #debug concat("\n","SUGGESTED RENDERING EXAMPLES:","\n") #debug concat("\n",str(50*XYZ_SIZE_.x,0,0)," X ",str(50*XYZ_SIZE_.z,0,0)," pixels with "str(50*XYZ_SIZE_.y,0,0)," slices (low quality)","\n", " (creates ",str(50*XYZ_SIZE_.x * 50*XYZ_SIZE_.y * 50*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(50,XYZ_SIZE_) #debug concat("\n",str(100*XYZ_SIZE_.x,0,0)," X ",str(100*XYZ_SIZE_.z,0,0)," pixels with "str(100*XYZ_SIZE_.y,0,0)," slices (low-to-medium quality) <<<=============","\n", " (creates ",str(100*XYZ_SIZE_.x * 100*XYZ_SIZE_.y * 100*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(100,XYZ_SIZE_) #debug concat("\n",str(150*XYZ_SIZE_.x,0,0)," X ",str(150*XYZ_SIZE_.z,0,0)," pixels with "str(150*XYZ_SIZE_.y,0,0)," slices","\n", " (creates ",str(150*XYZ_SIZE_.x * 150*XYZ_SIZE_.y * 150*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(150,XYZ_SIZE_) #debug concat("\n",str(200*XYZ_SIZE_.x,0,0)," X ",str(200*XYZ_SIZE_.z,0,0)," pixels with "str(200*XYZ_SIZE_.y,0,0)," slices","\n", " (creates ",str(200*XYZ_SIZE_.x * 200*XYZ_SIZE_.y * 200*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(200,XYZ_SIZE_) #debug concat("\n",str(250*XYZ_SIZE_.x,0,0)," X ",str(250*XYZ_SIZE_.z,0,0)," pixels with "str(250*XYZ_SIZE_.y,0,0)," slices","\n", " (creates ",str(250*XYZ_SIZE_.x * 250*XYZ_SIZE_.y * 250*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(250,XYZ_SIZE_) #debug concat("\n",str(275*XYZ_SIZE_.x,0,0)," X ",str(275*XYZ_SIZE_.z,0,0)," pixels with "str(275*XYZ_SIZE_.y,0,0)," slices","\n", " (creates ",str(275*XYZ_SIZE_.x * 275*XYZ_SIZE_.y * 275*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(275,XYZ_SIZE_) #debug concat("\n",str(300*XYZ_SIZE_.x,0,0)," X ",str(300*XYZ_SIZE_.z,0,0)," pixels with "str(300*XYZ_SIZE_.y,0,0)," slices","\n", " (creates ",str(300*XYZ_SIZE_.x * 300*XYZ_SIZE_.y * 300*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(300,XYZ_SIZE_) #debug concat("\n",str(325*XYZ_SIZE_.x,0,0)," X ",str(325*XYZ_SIZE_.z,0,0)," pixels with "str(325*XYZ_SIZE_.y,0,0)," slices","\n", " (creates ",str(325*XYZ_SIZE_.x * 325*XYZ_SIZE_.y * 325*XYZ_SIZE_.z,0,0)," voxels max)","\n") EXCESS(325,XYZ_SIZE_) #end // of #if(frame_number !=0 & INITIAL_LINEUP_) #if(INITIAL_LINEUP_) object{SLICE_OBJ_ #if(USE_CUTAWAY_TEXTURES_) finish{ambient 1 emission 0 diffuse 0} #else // This TEXTURE wrapper is required for v3.7 texture{DFLT_TXTR_ pigment{rgb 1} } #end } box{MIN_BB_ - .2*y,MAX_BB_ + .2*y pigment{rgbt <2,.25,.3,.75>} finish{ambient 1 emission 0 diffuse 0}} #else // the slicing code intersection{ object{SLICE_OBJ_ finish{ambient 1 emission 0 diffuse 0}} // the intersecting thin horizontal box (ZERO thickness). The camera sees // the bottom surface of each slice, and the slices proceed from the bottom up. box{, } #if(USE_CUTAWAY_TEXTURES_) cutaway_textures #else texture{ DFLT_TXTR_ pigment{SLICE_OBJ_COLOR_} } #end } // end of intersection and SLICING #end // of #if(INITIAL_LINEUP_) // automatically centers the camera under the center of the bounding box #if(INITIAL_LINEUP_ & XYZ_SIZE_.z >= XYZ_SIZE_.x) #declare CAM_Y_ = (MAX_BB_.z - MIN_BB_.z); #else #declare CAM_Y_ = (MAX_BB_.x - MIN_BB_.x); #end camera { orthographic // REQUIRED location look_at right x*image_width/image_height direction z angle 14.3// [14.3 exactly-- DO NOT CHANGE THIS-- it leaves a 1 or 2 pixel black 'safety' border around all 4 edges of the render(s)] } /* #if(frame_number=0) // i.e., no animation #debug concat("\n","camera location = <",vstr(3,,", ",0,4),">","\n") #debug concat("camera look_at = <",vstr(3,,", ",0,4),">","\n\n") #else #end */ //------ END OF CODE ------