User:Le Forgeron

From POV-Wiki
Jump to navigation Jump to search

I use this page to pre-document some experimental code (as experimental, not distributed in official release)

The code is available via:

They both have a wiki about the repository, read it too.

HgPovray 3.8

Dedicated page for HgPovray based on 3.8

Interesting documents & link

They should not be incorporated as such in the documentation, but can provide some interesting informations


Splines

Imported from Megapov
Relicensing from ABX is needed before allowing distribution
(some bugs get fixed in the process)
Also check the megapov documentation for better explanation or clarification.

LeForgeronSpline03.png LeForgeronSpline09.png LeForgeronSpline10.png LeForgeronSpline11.png

Accessing splines data

Not only the value of a spline can be evaluated with the traditional SPLINE_IDENTIFIER ( FLOAT [, SPLINE_TYPE] ), it is also possible to get back the actual pieces of information from a spline.

dimension_size( SPLINE_IDENTIFIER ) provides the number of entries in the spline.

For each entry, the spline can be accessed like an array, the first element is the float of the path list and the second element the associated vector.

  • SPLINE_IDENTIFIER[ INDEX ][0] is a float
  • SPLINE_IDENTIFIER[ INDEX ][1] is a vector
  • INDEX should evolve as an integer from 0 to dimension_size(SPLINE_IDENTIFIER)-1

Additional types of splines

Sor spline

LeForgeronSpline12.png

the curve followed by a sor can be evaluted by a spline of sor_spline type with a bit of manipulation: the y value of the sor must be used as the float of the path, and the x value become one of the component of the vector. The component of the vector never get negative with a sor spline.

spline{
   sor_spline
  -1.000000,0.000000*x
   0.000000,0.118143*x
   0.540084,0.620253*x
   0.827004,0.210970*x
   0.962025,0.194093*x
   1.000000,0.286920*x
   1.033755,0.468354*x
}

sor{
  7
  <0.000000, -1.000000>
  <0.118143,  0.000000>
  <0.620253,  0.540084>
  <0.210970,  0.827004>
  <0.194093,  0.962025>
  <0.286920,  1.000000>
  <0.468354,  1.033755>
}
akima spline

LeForgeronSpline00.png

That spline will go through all its points, smoothly.

spline {
  akima_spline
  time_Val_1, <Vector_1> [,]
  time_Val_2, <Vector_2> [,]
    ...
  time_Val_n, <Vector_n>
}
tcb spline

LeForgeronSpline13.png LeForgeronSpline14.png LeForgeronSpline15.png LeForgeronSpline16.png LeForgeronSpline17.png

Also know as Kochanek-Bartels spline, tcb stand for tension, continuity and bias.

The first and last point of such spline are not reached.

spline {
  tcb_spline [TCB_PARAMETERS]
  time_Val_1 [TCB_PARAMETERS], <Vector_1> [TCB_PARAMETERS][,]
  time_Val_2 [TCB_PARAMETERS], <Vector_2> [TCB_PARAMETERS][,]
    ...
  time_Val_n [TCB_PARAMETERS], <Vector_n> [TCB_PARAMETERS]
}

TCB_PARAMETERS:
  [tension FLOAT] [continuity FLOAT] [bias FLOAT]

The tension, continuity and bias are fully optional. Depending on the place where they appear, they control the spline in different ways:

  • Placed right after the tcb_spline keyword, they set the default values for all ends of the spline segments. This placement is ignored in case of copying spline without adding new controls because previous defaults were already propagated to each side of control points.
  • Placed between the time_value and the corresponding vector, the tcb parameters determine the properties of the spline segment ending in the vector that follows these parameters (as well as for the spline segment beginning at this vector if not overriden with the third position).
  • For tcb parameters following a vector, the properties of the spline segment beginning after this vector are set.

What is controlled by these parameters?

  • tension controls how sharply the curve bends.
  • continuity controls how rapid speed and direction change.
  • bias controls the direction of the curve as it passes through the control point.
x splines

X-Splines are an alternative to traditional splines that was introduced by Carole Blanc and Christophe Schlick in 1995.

XSplines have the very nice property that they can interpolate (go through) a control point as well as just approximate it. Sharp edges are also possible, but the curve is always C2 continuous, hence the sharp edges are only possible when the first derivative drops to zero.

An X-Spline is completely defined by a set of control point (vertices) and a set of parameters. One parameter is associated with each control point.

There is 3 variations of x splines:

  • basic
  • extended
  • general
basic x spline

The first and last point of such spline are not reached.

LeForgeronSpline01.png LeForgeronSpline02.png

spline {
  basic_x_spline [freedom_degree FLOAT]
  time_Val_1, <Vector_1> [freedom_degree FLOAT] [,]
  time_Val_2, <Vector_2> [freedom_degree FLOAT] [,]
  ...
  time_Val_n, <Vector_n> [freedom_degree FLOAT]
}

The freedom_degree before the first point is the default value (0.0 by default)

extended x spline

LeForgeronSpline04.png LeForgeronSpline05.png

Extended spline are always C², but allows sharp points (where both the first and second derivatives drop to zero). All the points are visited.

spline {
  extended_x_spline [freedom_degree FLOAT]
  time_Val_1, <Vector_1> [freedom_degree FLOAT] [,]
  time_Val_2, <Vector_2> [freedom_degree FLOAT] [,]
  ...
  time_Val_n, <Vector_n> [freedom_degree FLOAT]
}

The freedom_degree before the first point is the default value (0.0 by default)

general x spline

LeForgeronSpline06.png LeForgeronSpline07.png LeForgeronSpline08.png

All points are visited.

spline {
  general_x_spline [freedom_degree FLOAT]
  time_Val_1, <Vector_1> [freedom_degree FLOAT] [,]
  time_Val_2, <Vector_2> [freedom_degree FLOAT] [,]
  ...
  time_Val_n, <Vector_n> [freedom_degree FLOAT]
}

The freedom_degree before the first point is the default value (0.0 by default)

Colour space interpolation

The colour interpolation is available for:

  • mesh
  • blob
  • polygon

It can be used with texture_map, pigment_map or colour_map.

The interpolation is performed between the resulting colours from the evaluation, not along the map.

Which colourspace ?

  • colour_space pov
  • colour_space hsl
  • colour_space hsv
  • colour_space xyl
  • colour_space xyv

color_space is also a valid synonym for colour_space.

pov

Classical linear interpolation in the rgb space.

50% of pure Red (rgb <1, 0, 0>) and pure Green (rgb <0, 1, 0 >) is a dark yellow (rgb <1/2, 1/2, 0>).

LeForgeronColSpaceRgb.png

hsl or hsv

The colour (from rgb space) is converted to the HSL ot HSV colour system where the linear interpolation is performed.

50% of pure Red and pure Green turns out as pure Yellow.

LeForgeronColSpaceHs.png

xyl or xyv

the hs part is considered as polar coordinates (h, hue, being the angle and s being the length) of a point. The interpolation is performed using the Cartesian coordinates (xy).

The interpolation for the l or v part remains unchanged, a simple linear interpolation.

LeForgeronColSpaceXy.png

Mesh

Only one colour space per mesh, used for all its triangles.

mesh {
	triangle {0,x,y texture_list { colo1, colo2, colo3 } }
        ...
	colour_space hsv
}

blob

Only one colour space per blob, used for all components.

blob {
  ...	
   	colour_space hsv
}

Interpolation for polygon

LeForgeronPolygon.png

a texture_list can be provided in the polygon, with a texture identifier for each vertex (and ignoring repeated vertex which are used to close a line)

The colour of any point from the polygon is a weighted average of each vertex, with the weight based on the distance to the vertex: the closer to a vertex, the more weight that vertex has. strength (with a float) can be used to adjust the relative weight by raising them to the power of the strength: strong strength gives more pronounced partitions.

#declare colo3=texture { pigment {color rgb<0.,0.,0>}};
#declare colo4=texture { pigment {color rgb<0.,1.,1/3>}};
#declare colo5=texture { pigment {color rgb<0.,1.,1>}};
#declare colo6=texture { pigment {color rgb<1.,1.,1/3>}};
#declare colo7=texture { pigment {color rgb<1.,1./3,1>}};
#declare num=5;
#declare step=2;
                                polygon { (num+1)*step,
#local j=0.70;
#while(j>0.1)
#local i=0;
#while(i<num+1)
		                j*< cos(i*2*pi/num),sin(i*2*pi/num),0>
#local i=i+1;
#end
#local j=j-0.90/step;
#end
			texture_list { colo3, colo4, colo5, colo6, colo7, colo5, colo6, colo7, colo3, colo4 } 
                        strength 1.0
}

colour_space is of course available too.

Access to camera information

These pieces of information are in read-only mode. You cannot use them to modify the actual value (no #declare or #local). The various vectors might have been updated by transform and look_at.

  • camera_type is a string containing the type of the camera (but not its subtype, so cylinder camera might be ambiguous).
  • camera_up is the actual up vector of the camera.
  • camera_right is the actual right vector of the camera.
  • camera_direction is the actual direction vector of the camera.
  • camera_location is the actual location of the camera.

In case of scene with multiple cameras, each keyword can be followed by an usual array notation to access the relevant camera. (e.g. camera_up[3] for the fourth camera)


Tesselation & mesh play

Yoda: Yes, run! Yes, a Jedi's strength flows from the Renderer. But beware of the dark side. 
      Mesh, Heightfield, Bicubic Patch; the dark side of the Force are they. Easily they flow, 
      quick to join you in a fight. If once you start down the dark path, 
      forever will it dominate your destiny, consume you it will, as it did Isosurface's apprentice.
Luke: Parametric precompute... Is the dark side stronger?
Yoda: No, no, no. Quicker, easier, more seductive.
Luke: But how am I to know the good side from the bad?
Yoda: You will know... when you are calm, at peace, passive. 
      A Jedi uses the Renderer for knowledge and defense, NEVER for attack.
Luke: But tell my why I can't...
Yoda: No, no! There is no "why".

Mesh from 3D finite object

  • it must be 3D, to have an inside test which is meaningfull
  • it must be finite, because the bounding box is use to specify the volume which will be sampled

Whatever the method used (it will always end as a mesh object, or inside a mesh object). there is some common parameters:

  • original is followed by the object to sample. It is really mandatory.
  • accuracy is followed by a 3D vector which specify the number of slices in each direction (it defaults to 10)
Without texture, using only Inside test (fast)

These approaches use a marching cube algorithm, hence their usage were forbidden on the USA thanks to a now expired patent (17 years after December 1987).

LeForgeronBourke.png

  • heller ( alternate table from Bourke page made by Geoffrey Heller)

LeForgeronHeller.png

  • cubicle (simplistic approach using a cube)

LeForgeronCubicle.png

  • cristal (same as cubicle, with inclined face)

LeForgeronCristal.png

bourke & heller allow additional options :

  • precision with a float, which supersample along the interecting line (by the amount of the float, so only positive integer are of any real interest) for a better fit.
  • offset is followed by a float which move outward the position of each face of the bounding box used for scanning (default to 0, so beware of very tight perfect bounding box)
Using Inside test & trace (slower)

No marching cube per itself here, the inside test is used to trigger the usage of trace to get the actual intersection.

  • tesselate

LeForgeronTesselate.png

 mesh { ...
  tesselate { 
    original finite3D_obj
    [accuracy vector] [albinos] [offset float] [smooth] [texture { Tid }]
  }
 ...
 }

OR

 tesselate { 
   original finite3D_obj
   [accuracy vector] [albinos] [offset float] [smooth] 

 [Object_Mods...]
 }
  • tessel

LeForgeronTessel.png

 mesh { ...
  tessel { 
    original finite3D_obj
    [accuracy vector] [albinos] [offset float] [smooth] [texture { Tid }]
  }
 ...
 }

OR

 tessel { 
   original finite3D_obj
   [accuracy vector] [albinos] [offset float] [smooth] 

 [Object_Mods...]
 }

As trace is used, the texture from the intersection point is available and can be pushed on the vertex of each generated triangle. This can be prevented with the use of the albinos option.

  • a possible parameter is smooth which would also use the normal reported by the intersection to make smooth_triangle instead of triangle in the resulting mesh.
  • offset is followed by a float which move outward the position of each face of the bounding box used for scanning (default to 0, so beware of very tight perfect bounding box)

Mesh from and to file

Loading

A GTS file can be loaded with gts_load.


#include "colors.inc"
camera { location <3,5,-4>
	direction z
		up y
		right image_width/image_height*x
		look_at <-1/2,1/2,0>
		angle 35
}

light_source{ <-5, 20, -20>, 1}
light_source{ <0, 2, 0>, 1/2}

gts_load{ "bunny.gts"
	right
	rotate 180*y	
	scale 17
	translate -2*y
	texture { pigment { color Aquamarine}}
}
LeForgeronGtsLoad.png

Aside from the filename of the file to load, the right keyword can be used to change the default left-handed coordinate system to a right-handed one.

gts_load can be used to create a mesh of its own or to incorporate the mesh of the file into a larger mesh, in which case a texture identifier can be applied over the loaded GTS mesh.

 mesh { ...
    gts_load { filename [right] [texture { Tid }] }
  ...
 }

OR

 gts_load { filename [right] 

 [Object_Mods...]
 }
Saving

A mesh can be saved with gts_save. Beware of I/O restrictions.

gts_save { filename, mesh_object }

GTS format saves the geometry, but neither the faked normal or the textures

Getting a new mesh from a mesh

The following method (or pseudo-object) can be used only on a mesh, whatever its origin.

Whatever the method used (it will always end as a mesh object, or inside a mesh object). there is some common parameters:

  • original is the mesh used as the base object (it is not updated, it is used as data source)
  • albinos is an option which remove all textures on the generated triangles
bend

Curve the mesh along a line, using a reference half-plane containing that line.

LeForgeronBend.png

bend  { original Objiii 
        origin 0  
        amount 30 
        fixed z 
        direction y
        minimal -0.0
        maximal 2.0 }
bend  { original Objiii 
        origin 0  
        amount 30 
        fixed y 
        direction z
        minimal -50.0
        maximal 2.0 }
 mesh { ...
   bend {
    original mesh_object
    [albinos]  [amount float]  [direction vector]  [fixed vector]  [maximal float]  [minimal float]
    [modulation { texture_description }]  [origin vector]  [texture { Tid }]
   } 
 ...
 }

OR

 bend {
  original mesh_object
  [albinos]  [amount float]  [direction vector]  [fixed vector]  [maximal float]  [minimal float]
  [modulation { texture_description }]  [origin vector]

 [Object_Mods...]
 } 
  • original mesh_object : the original mesh object whose data are used as source for the new mesh
  • albinos : do not copy the texture from the original mesh
  • amount float : angle of rotation (in degree) for a unit length. The rotation is proportional to the length.
  • direction vector : axis of the rotation, only the direction is taken into account.
  • fixed vector : axis of the zero-plane (origin, origin+direction & origin+fixed points are all contained inside the zero-plane: the plane with no transformation)
  • maximal float : when length is bigger, the transformation is limited to the float.
  • minimal float : when length is smaller, the transformation is limited to the float.
  • modulation { texture_description } : the luminosity of the colour from the texture evaluated at the vertex is used to ponder the deformation effect; full black means no transformation, white (<1,1,1>) means 100%.
  • origin vector : vertex used as the origin of the transformation's reference base.
displace

Move each vertex of a triangle along its normal.

Be careful: as a vertex might appears in more than one triangle, if the normal at a vertex is not the same for all the triangles sharing that vertex, the displacement would create cracks in the resulting mesh as each triangles move away.

LeForgeronDisplace.png

 mesh{ ...
  displace {
    modulation { texture_description }
    original mesh_object
    [albinos]  [amount float]  [offset float] [inside_point vector] [texture { Tid } ]
  }
  ...
 }

OR
 
 displace {
  modulation { texture_description }
  original mesh_object
  [albinos] [amount float] [offset float] [inside_point vector]

 [Object_Mods...]
 } 
  • original mesh_object : the original mesh object whose data are used as source for the new mesh
  • modulation { texture_description } : the luminosity of the colour from the texture evaluated at the vertex is used to ponder the deformation effect; full black means no transformation, white (<1,1,1>) means 100%.
  • albinos : do not copy the texture from the original mesh
  • amount float : length of displacement for 100%.
  • offset : offset applied to the luminosity. (default value is 0.5, so full black is -50% and white is 50%)
  • inside_point : when present, normals are flipped (for the displacement) whenever it would not be centrifuge with the vector of the position relative to the inside_point. Allow to get consistent displacement on mesh with random normal distribution.
move

Transforms the coordinates of each points.

mesh { ...
  move {
   original mesh_object
   [albinos] [modulation { texture_description } ] [move < coeff_of_matrix(12) >] [ texture { Tid } ]

} 
  ...
}

OR

move {
    original mesh_object
    [ albinos ] [modulation { texture_description } ] [ move < coeff_of_matrix(12) > ]

[Object_Mods...]
} 

The starting point is used with the move matrix to produce a end point. The resulting deplacement is then modulated by the luminosity of the modulation texture to produce the final point.

The matrix is the usual transformation matrix.

#include "colors.inc"
#default { finish { ambient 0.5 specular 0.5 } }
camera { location <6,6,12> direction  -z right x up y look_at 0 angle 25 }
light_source { <-30,100,50>, 1 }

#declare tt=texture { pigment { spiral2 6 scale 2 translate -y*0.95 pigment_map { 
[0 Black]
[1 Gray20]
} } }
 
#declare msize=3.0;
move { original cristal { accuracy 150 original sphere { 0,msize } }
modulation { tt }
move < 0.6,+0.4,0, 0,1,0, 0,-0.2,0.1, 0,0,0 >
pigment { Yellow } 
}
LeForgeronMove.png
planet

To Do : illustration and explanation.

roll

LeForgeronRoll.png

  • original mesh_object : the original mesh object whose data are used as source for the new mesh
  • albinos : do not copy the texture from the original mesh
  • modulation { texture_description } : the luminosity of the colour from the texture evaluated at the vertex is used to ponder the deformation effect; full black means no transformation, white (<1,1,1>) means 100%.
  • direction vector : vector of the rotation (as usual) for a unit length along that vector.
  • maximal float : when rotation's angle is bigger, the transformation is limited to the float.
  • minimal float : when rotation's angle is smaller, the transformation is limited to the float.
  • origin vector : vertex used as the origin of the transformation's reference base.
mesh{ ...
  roll {
    original mesh_object
    [albinos] [direction vector] [maximal float] [minimal float] [modulation { texture_description }]
    [origin vector]
    [texture { Tid }]
  }
  ...
}

OR

roll {
    original mesh_object
    [albinos] [direction vector] [maximal float] [minimal float] [modulation { texture_description }]
    [origin vector]

[Object_Mods...]
}
screw

LeForgeronScrew.png

#default { pigment { rgb <1,.8,.6> } finish { specular .5 } }
#declare Objiii = cubicle { original box { <-0.5,-3.5,-0.5>,<0.5,3.5,0.5>  } accuracy <20,120,20> }
#local i=0;
#while (i<15)
screw  { original Objiii origin 0  direction i*20*y
  #if (mod(i,3)=1) minimal -30.0 maximal i*45.0 #end
  #if (mod(i,4)=0) right #end
rotate 30*x*mod(i+1,2)  translate i*2*x } 
#local i=i+1;
#end
camera { location <14.0,0,150> up 8*y right 8*x*image_width/image_height direction -z angle 12 }
light_source { <200,100,-150>, z }
light_source { <00,10,150>, 1 }
light_source { <200,100,100>, x }
light_source { 0, y }
  • original mesh_object : the original mesh object whose data are used as source for the new mesh
  • albinos : do not copy the texture from the original mesh
  • modulation { texture_description } : the luminosity of the colour from the texture evaluated at the vertex is used to ponder the deformation effect; full black means no transformation, white (<1,1,1>) means 100%.
  • direction vector : vector of the rotation (as usual) for a unit length along that vector.
  • maximal float : when rotation's angle is bigger, the transformation is limited to the float.
  • minimal float : when rotation's angle is smaller, the transformation is limited to the float.
  • origin vector : vertex used as the origin of the transformation's reference base.
  • right : inverse the handedness of the the screw (on a default left-handed scene, the default screw is the traditional clockwise; right allows to produce the chiral one)


mesh{ ...
  screw {
    original mesh_object
    [albinos] [direction vector] [maximal float] [minimal float] [modulation { texture_description }]
    [origin vector] [right]
    [texture { Tid }]
  }
  ...
}

OR

screw {
    original mesh_object
    [albinos] [direction vector] [maximal float] [minimal float] [modulation { texture_description }]
    [origin vector] [right]

[Object_Mods...]
}
keep

LeForgeronKeep.png

Keep only part(s) of a mesh, relative to a 3D object. Four parts are possible:

  • inner all 3 vertices of a triangle are inside the 3D object.
  • inbound only 2 vertices of a triangle are inside.
  • outbound only 1 vertex of a triangle is inside.
  • outside all 3 vertices of a triangle are not inside the 3D object.

A keep selection can select as many parts as wanted for the resulting mesh, but will only use a single 3D object.

keep { original Foobar_Mesh 
  with intersection { 
            box { <-1,-1,-1>,<4,haut+1,0.04> } 
            sphere { <1.5,haut/2,0>,haut*2/5 }
       }
   outside
}


mesh{ ...
  keep {
    original mesh_object
    with solid_object
    [albinos] [inbound] [inner] [outbound] [outside]
    [texture { Tid }]
  }
  ...
}

OR

keep {
    original mesh_object
    with solid_object
    [albinos] [inbound] [inner] [outbound] [outside]

[Object_Mods...]
}
smooth

LeForgeronSmooth.png

#include "colors.inc"
background { rgb z *.5}
#declare T1= texture { pigment { rgb <1,.8,.6> } finish { specular .5 } };
#declare T2= texture { pigment { rgb <.8,.6,1> } finish { specular .5 } };
#declare T3= texture { pigment { rgb <.6,1,.8> } finish { specular .5 } };
#default { texture { T1 }}
#declare Obj = sphere { 0,1 texture { T3} }
#declare Spacing = 2.1;
#declare Tes= tessel { original Obj accuracy 3 offset 0.1 albinos texture { T2 } }
object { Obj translate x*4*Spacing }

object { Tes translate -x*Spacing }
#for(i,0,3,1)
smooth { original Tes method i translate Spacing*x*i }
#end

camera { orthographic location < 0, 4, -18 > *2.1 up y right image_width/image_height*x
look_at < 0, 0, 0 > angle 37 / 2 translate Spacing*x*1.5 }
light_source { <200, 100, -150 >, 1}
light_source { <-200, 100, -100 >, x * .5}
mesh{...
  smooth {
    original mesh_object
    [albinos] [amount float] [method float] [texture { Tid }]
  } 
...
}

OR

smooth {
    original mesh_object
    [albinos] [amount float] [method float ]

  [Object_Mods...]
} 

Perturbate the normal of each triangle. By default the perturbation is toward a smoother surface.

  • amount float : the amount of displacement of the normals toward the unified normal at that vertex. 1 (=100%) by default.
  • method index : how to compute the unified normal (default to 0)
    • 0 : basic average of all contributing normals
    • 1 : weighted average, the weight is the angle at the vertex
    • 2 : weighted average, the weight is the product of the lengths of segments at the vertex
    • 3 : weighted average, the weight is the surface of the triangle
warp

LeForgeronWarp.png

#version 3.7;
global_settings { assumed_gamma 1.0 }
#include "colors.inc"

camera { location <9.3,1.5/2,-100> up y direction z
right image_width/image_height*x look_at <9.3,1.5/2,0> angle 11 }
#declare T0= texture { pigment { Gold } }

light_source { <-30,100,-100>,1 }
light_source { <0,00,-100>,1 }

#declare Obj1= union {
        box { <0,0,0>,<1,1.5,30> texture { pigment { Blue } } }
        box { <1,0,0>,<2,1.5,30> texture { pigment { White } } }
        box { <2,0,0>,<3,1.5,30> texture { pigment { Red } } }
        box { <1.45,0.3,-0.001>,<1.55,1.2,0> texture { T0 } }
        box { <1.2,0.70,-0.001>, <1.8,0.80,0> texture { T0 } }
        box { <1.325,0.925,-0.001>, <1.675,1.025,0> texture { T0 } }
      }

#declare Vector =  <0.1,0.2,0.3>;

#declare Boring_mesh= keep { original tesselate { original  Obj1 offset 0.1 accuracy <100,50,2> }
		with box { <-1,-1,-1>,<4,1.5+1,0.04> } inner };

object { Boring_mesh  }
#for(i,1,5,1)
warp { original Boring_mesh warp { turbulence Vector octaves i } 
			 translate 3.15*i*x }
#end
mesh{...
  warp {
    original mesh_object warp warp_description
    [albinos] [modulation { texture_description } ] [move <coeff_ot_matrix(12)>] [texture { Tid }]
  } 
...
}

OR
warp {
    original mesh_object warp warp_description
    [albinos] [modulation { texture_description } ] [move <coeff_ot_matrix(12)>]
    
  [Object_Mods...]
} 

See move for the details about modulation. The matrix provided with move is applied to the points before evaluating the warp (useful in animation for moving an object in the wind: as the wind progress, the translation of the matrix does also).

proximity pattern

#declare test_object = 
  julia_fractal {
    <0.1,0.8,-0.1,0.002> quaternion sqr
    max_iteration 8
    precision 1000
    scale 60 translate y*60 rotate y*45
}

object {  test_object
  texture {
    proximity { test_object } radius 10
    texture_map {
      [ 0.0 pigment { rgb <0,169,224>/255 } ]
      [ 0.2 pigment { rgb <50,52,144>/255 } ]
      [ 0.4 pigment { rgb <234,22,136>/255 } ]
      [ 0.6 pigment { rgb <235,46,46>/255 } ]
      [ 0.8 pigment { rgb <253,233,45>/255 } ]
      [ 1.0 pigment { rgb <0,158,84>/255 } ]
    }
  }
}

LeForgeronProximity.png

proximity { Object_Description } [ PATTERN_MODIFIER | radius Radius_of_Sampling ]...

The default radius of sampling is 1.0. A weighted sampling is performed inside the sphere around the intersection, returning a value between 0.0 (all insideness tests failed) and 1.0 (all tests succeed). Usual value (for flat surface) would be around 0.5, edge of box dropping to 0.25 and corners of box to 0.125 (1/8 of the sphere).

Getting a copy of an object inside a CSG

A small SDL extension, to retrieve the object inside an existing CSG.

child { CSG_Object_ID }( Index )

The index start at 0 for the first child of the CSG. Only the first level of the CSG is explored (recursion in CSG structure must be handled the same way: with recursion).

patterns with list of objects

binary { OBJECT_LIST } [ PATTERN_MODIFIERS ]

proportion { OBJECT_LIST } [ PATTERN_MODIFIERS ]

OBJECT_LIST = Object_Description [ OBJECT_LIST ]

LeForgeronProportionAndBinary.png

proportion pattern

For a list of N objects, perform an insideness test for each of them and compute a number k/N, where k is the number of success for insideness test.

binary pattern

Take into account the position of the object in the list to weight it.

As for proportion, it use insideness testing. but the contribution of the k-th object is 1/(2^k).

The value is 1 if all tests succeed, and has a lower limit of 1/(2^N) (which tends to 0 very rapidly).

Vault

User:Le_Forgeron/vault

Camera

You knew orthographic, ultra_wide_angle, spherical, omnimax, fisheye, perspective and others, here a few new kinds.

The recommendation about the ratio is for the the final picture's dimensions, assuming square pixels.

Put the location above the intended center, in orbit. The location+direction should provide the center of the planet.

LeForgeronCamera perspective.png

aitoff_hammer

Recommended ratio is 2:1

LeForgeronCamera aitoff hammer.png

eckert_iv

Recommended ratio is 2:1

LeForgeronCamera eckert iv.png

eckert_vi

Recommended ratio is 2:1

LeForgeronCamera eckert vi.png

lambert_azimuthal

Recommended ratio is 1:1

LeForgeronCamera lambertazi.png

mercator

Recommended ratio is up to you, as you need a very large height/wide to hope reaching the poles (nah, it's impossible with that projection).

LeForgeronCamera mercat.png

miller_cylindrical

Recommended ratio is 1.3638862 or 1:0.733

LeForgeronCamera miller.png

mollweide

Recommended ratio is 2:1

LeForgeronCamera mollweide.png

plate_carree

Recommended ratio is 2:1

LeForgeronCamera platecarree.png

van_der_grinten

Recommended ratio is 1:1

LeForgeronCamera van der grinten.png


Cylindrical Equal Area Projection

formula for ratio is π.cos²(φ) with φ the standard parallel.

balthasart

Recommended ratio is about 1.3.

The standard parallel of the projection is 50°.

LeForgeronCamera balthasart.png

behrmann

Recommended ratio is 3π:4 (about 2.36)

The standard parallel of the projection is 30°.

LeForgeronCamera behrmann.png

edwards

Recommended ratio is about 2.

The standard parallel of the projection is 37°24'.

LeForgeronCamera edwards.png

gall

Recommended ratio is π:2 or golden ratio (φ) (both near 1.6).

The standard parallel of the projection is 45°.

LeForgeronCamera gall.png

hobo_dyer

Recommended ratio is about 2.

The standard parallel of the projection is 37°30'.

LeForgeronCamera hobo dyer.png

lambert_cylindrical

Recommended ratio is π

The standard parallel of the projection is 0°.

LeForgeronCamera lambertcyl.png

peters

Recommended ratio is about π:2 or golden ratio φ (not exactly the same thing, but around 1.6).

The standard parallel of the projection is 44.138°.

LeForgeronCamera peters.png

smyth_craster

Recommended ratio is about 2.

The standard parallel of the projection is 37°04'.

LeForgeronCamera smyth craster.png

Unfolding platonic

Of the 5 platonic solids, 4 are easy to unfold to make a map. The dodecahedron is not available so far.

icosa

Recommended ratio is about 2.1169 ( 11.sqrt(3):9 )

LeForgeronCamera icosa.png

octa

Recommended ratio is about 2.3 ( 4:sqrt(3) )

LeForgeronCamera octa.png

cube

Recommended ratio is 2.5 ( 5:2 )

LeForgeronCamera cube.png


tetra

Recommended ratio is about 2.886 ( 5:sqrt(3) )

LeForgeronCamera tetra.png

Stereoscopic camera

The right's length is adjusted automatically to take into account that there is two images. Just use the same right you would with a picture of half the width. Or think of it the other way : the view is HxW, the rendering is to be done for a Hx(2W).

camera
{ stereo distance (clock <0 ? -26:26 )
  parallaxe atan2(13*clock,300)
 location -300*z
 right image_width/image_height*x
 direction z
 up y
 angle 15
 }

LeForgeronStereoCrossed.png

cross-eyed viewing:
distance is negative

LeForgeronStereoFocus.png

Parallel viewing:
distance is positive

LeForgeronStereoParallel.png

Parallel viewing with 0 parallaxe
  • distance provides the distance, along the right axis's direction, between the eyes. The location of the camera is the middle point.
    • use a positive value for parallel viewing
    • use a negative value for cross-eyed viewing
    • default is 0
  • parallaxe is the angle between the eyes's direction:
    • should normally be of the same sign of distance
    • normal value is atan2( half distance value, distance to focus )
    • default is 0

RefImgCameraViewStereo.png

Omni Directional Stereo camera

camera
{ omni_directional_stereo distance 1
 location 0
 up 10*y
 right 10*x
 direction 10*z
 }

LeForgeronODS.png

ODS picture
  • distance provides the distance, along the right axis's direction, between the eyes. The location of the camera is the middle point.

HowTo

Sections with HowTo in preparation

Patterns like crackle

voronoi

voronoi pattern with points specified in the SDL (no randomness).

Syntax is :

voronoi { <pt1>,<pt2>, .... <ptN> }

<ptX> is a 3D vector

Number of points must be at least 2, but the number does not have to be provided.

For N points, returns in the range 0 to 1 the value k/(N-1) where k is ordinal of the first point with the smallest distance (first := 0, last := N-1 )

  • first point, because any <ptX> could be a duplicate value of a previous one in the list.

LeForgeronVoronoi.png

#version 3.7;
global_settings{ assumed_gamma 1.0 }

#declare seeds=seed(33);
#include "colors.inc"
background { Aquamarine }

#declare Tex= texture { voronoi { 
#for(zx,-15,15,7.5)
#for(zy,-15,15,7.5)
#for(zz,-15,15,7.5)
#if (rand(seeds)<0.15)
	<zx, zy, zz >,
#end
#end
#end
#end
}
texture_map{
	[0.0 pigment { color Blue } ]
		[0.3 pigment { color Cyan } ]
		[0.5 pigment { color Green } ]
		[0.7 pigment { color Yellow } ]
		[1.0 pigment { color Red } ]
}
} 

difference { superellipsoid { <0.025,0.025> scale 10 } 
box { <-3,-3,-11>,<3,3,11>  rotate -10*z}
box { <-11,-4,-4>,<11,4,4>  rotate -20*x}
box { <-5,-11,-5>,<5,11,5> rotate 30*y}

texture { Tex scale 6/11}
}
camera { location 50*y+060*x-100*z direction z up y right image_width/image_height*x look_at <0,0,0> angle 20 }


light_source { <-4,8,-2>*100, 1 area_light 40*x,40*z, 7,7 circular orient }
light_source { <4,8,-2>*100, 3/4 area_light 40*x,40*z, 7,7 circular orient }
light_source { <4,80,-2>*100, 1/2 area_light 40*x,40*z, 7,7 circular orient }

masonry

masonry pattern with points & map value specified in the SDL (no randomness): think crackle pattern, with seam, under absolut control of the SDL

Syntax is:

masonry <3D-vector> { <4D-pt1>,<4D-pt2>,...<4D-ptN> }
3D-vector.x
width of the seam (in absolut pov unit) between any adjacent cells
3D-vector.y
value of map at the very center of the seam
3D-vector.z
value of map at the transition between a cell and the seam
linear interpolation along the seam does happen
Each 4D-pt vector
the 3D point, seed of the voronoi cell, expanded with the value on the map to be return for the whole cell.

if two adjacent cells have the same value, the seam between them is removed, allowing to make concave cell.

LeForgeronMasonry.png

#version 3.7;
global_settings{ assumed_gamma 1.0 }

#declare seeds=seed(33);
#include "colors.inc"
background { Aquamarine }

#declare Tex= texture { masonry <0.2,1,0.99> { 
#for(zx,-15,15,1)
#for(zy,-15,15,1)
#for(zz,-15,15,1)
#if (rand(seeds)< 0.01250)
	<zx, zy, zz ,(rand(seeds)*0.98)>,
#end
#end
#end
#end
}
texture_map{
	[0.0 pigment { color Blue } ]
		[0.3 pigment { color Cyan } ]
		[0.5 pigment { color Green } ]
		[0.7 pigment { color Yellow } ]
		[0.99 pigment { color Magenta } ]
		[0.990 pigment { color White } ]
		[0.994 pigment { color White } ]
		[0.998 pigment { color Red } ]
		[1.0 pigment { color Red } ]
}
} 

difference { superellipsoid { <0.025,0.025> scale 10 } 
box { <-3,-3,-11>,<3,3,11>  rotate -10*z}
box { <-11,-4,-4>,<11,4,4>  rotate -20*x}
box { <-5,-11,-5>,<5,11,5> rotate 30*y}

texture { Tex scale 6/11}
}
camera { location 50*y+060*x-100*z direction z up y right image_width/image_height*x look_at <0,0,0> angle 20 }


light_source { <-4,8,-2>*100, 1 area_light 40*x,40*z, 7,7 circular orient }
light_source { <4,8,-2>*100, 3/4 area_light 40*x,40*z, 7,7 circular orient }
light_source { <4,80,-2>*100, 1/2 area_light 40*x,40*z, 7,7 circular orient }


LeForgeronMasonry2.png

#version 3.7;
global_settings{ assumed_gamma 1.0 }

#declare seeds=seed(33);
#include "colors.inc"
background { Aquamarine }
camera { location 50*y+060*x-100*z
direction z
up y
right image_width/image_height*x
look_at <0,0,0>
angle 20
}


light_source { <-4,8,-2>*100, 1 
area_light 40*x,40*z, 7,7 circular orient
}
light_source { <4,8,-2>*100, 3/4 
area_light 40*x,40*z, 7,7 circular orient 
}
light_source { <4,80,-2>*100, 1/2 
area_light 40*x,40*z, 7,7 circular orient 
}

#declare Tex=
 texture {
masonry <0.05,1,0.999> { 
#for(ty,-10,10,1)
#local k=rand(seeds)*0.98;
#local k2=rand(seeds)*0.98;
#local k3=rand(seeds)*0.98;
#for(tx,0,359,7.5)
#local zy=ty;
#local zx= 4.5*cos(radians(tx+7.5*ty))-12;
#local zz= 4.5*sin(radians(tx+7.5*ty));

#local ax= 4.5*cos(radians(tx+7.5*ty))+7;
#local ay= 4.5*sin(radians(tx+7.5*ty));
#local az= ty;
#local bx= 3.5*cos(radians(tx+7.5+7.5*ty))+7;
#local by= 3.5*sin(radians(tx+7.5+7.5*ty));
#local bz= ty;
#if (0=mod(tx,15))
#local k=rand(seeds)*0.98;
#local k2=rand(seeds)*0.98;
#local k3=rand(seeds)*0.98;
#end
<zx, zy, zz ,k>,
<-zx,zy,zz,k2>,
//#if (abs(ty)>=3)
<ax,ay,az,k3>,
<bx,by,bz,k>,
//#end
#end
#end
}
texture_map{
[0.0 pigment { color Red } ]
[0.99 pigment { color IndianRed } ]
[0.990 pigment { color White } ]
[0.994 pigment { color White } ]
[0.999 pigment { color Black } ]
[1.0 pigment { color White } ]
}
} 
difference{
union {
cylinder { <-12,-10,0>,<-12,10,0>,5}
cylinder { <12,-10,0>,<12,10,0>,5}
cylinder { <7,0,-10>,<7,0,10>,5}
}
cylinder { <-12,-11,0>,<-12,11,0>,3}
cylinder { <12,-11,0>,<12,11,0>,3}
cylinder { <7,0,-11>,<7,0,11>,3}
texture { Tex }
}

Warp

direct to a surface

cone

wrap around a circular cone (oriented along y axis) with apex at origin point and a radius of unit_base one unit away from that apex. The x=0 half-plane (for z>0) remains itself.

Each axis of parameter is the multiplying factor for that axe.

warp { cone <origin>,unit_base,<parameter> }
cone { <0,2,0>,0,<0,0,0>,1
texture { pigment { My_pigment 
warp { cone <0,2,0>,0.5,<3,5,7> }
}
}
}
cone { <0,2,0>,0.5,<0,0,0>,1
texture { pigment { My_pigment 
warp { cone <0,4,0>,0.25,<3,5,7> }
}
}
}

LeForgeron warpcone2.png

LeForgeron warpcone.png

LeForgeron warpcutcone2.png

LeForgeron warpcutcone.png

cylinder

wrap around a cylinder (oriented along y axis) with <0,0,0> moved at origin point. The x=0 half-plane (for z>0) remains itself.

Each axis of parameter is the multiplying factor for that axe.

warp { cylinder <origin>,<parameter> }
cylinder { <0,0,0>,<0,2,0>,1
 texture { pigment { My_pigment 
  warp { cylinder <0,1,0>,<3,5,7> }
}
}
}

LeForgeron warpcyl.png

LeForgeron warpcutcyl.png

sphere

wrap around a sphere (main axe being the y axe) with <0,0,0> moved at origin point. The x=0 half-plane (for z>0) remains itself.

Each axis of parameter is the multiplying factor for that axe.

warp { sphere <origin>,<parameter> }
sphere { <0,0.5,0>,1
 texture { pigment { My_pigment 
  warp { sphere <0,0.5,0>,<3,5,7> }
}
}
}

LeForgeron warpsphe.png

LeForgeron warpcutsphe.png

torus

wrap around a torus (oriented along y axis) with <0,0,0> moved at origin point and a major radius of major. The x=0 half-plane (for z>0) remains itself.

Each axis of parameter is the multiplying factor for that axe.

warp { torus <origin>,major,<parameter> }
torus { 0.55,0.45 
 texture { pigment { My_pigment 
  warp { torus <0,0,0>,0.55,<3,5,7> }
}
}
}

LeForgeron warptorus.png

LeForgeron warpcuttorus.png

GSD : Generalised Symetric Difference

RANGE: (NUMBER|VECTOR)[,RANGE]
VECTOR: <NUMBER, NUMBER>
NUMBER: number of intersection, negative number are added to total number of object+1

The minimal number of objects is three.

LeForgeronGSD.png

Interunion

syntax is

interunion { 
  OBJECTS...
  [range{ RANGE } ]*
  [OBJECT_MODIFIERS...] 
 }
#version 3.7;
global_settings { assumed_gamma 1.0 }

camera { location -560*z
direction z
up y
right image_width*x/image_height
angle 5
}

#include "colors.inc"

interunion{
#for(i,0,359.99,60)
#local pos= vrotate(6*x,i*z);
cylinder { pos-z,pos+31*z,10 texture { pigment { color CH2RGB(i) filter 0.45 } } }
#end
range { <2,4> }
clipped_by {cylinder { 30*z,0, 20  } }
}
box { 30*z-20*x-20*y, 30*z+20*x+20*y texture { pigment { color White }}}

light_source { 10*<0,0,-20>, 0.9 }
light_source { 10*<-5,10,-50>, 0.9 }
light_source { 10*<-10,10,-50>, 0.9 }
light_source { 10*<5,10,-50>, 0.9 }
light_source { 10*<10,10,-50>, 0.9 }
LeForgeronInterunion.png

Intermerge

syntax is

intermerge { 
  OBJECTS...
  [range{ RANGE } ]*
  [OBJECT_MODIFIERS...] 
 }
#version 3.7;
global_settings { assumed_gamma 1.0 }

camera { location -560*z
direction z
up y
right image_width*x/image_height
angle 5
}

#include "colors.inc"

intermerge{
#for(i,0,359.99,60)
#local pos= vrotate(6*x,i*z);
cylinder { pos-z,pos+31*z,10 texture { pigment { color CH2RGB(i) filter 0.45 } } }
#end
range { <2,4> }
clipped_by {cylinder { 30*z,0, 20  } }
}
box { 30*z-20*x-20*y, 30*z+20*x+20*y texture { pigment { color White }}}

light_source { 10*<0,0,-20>, 0.9 }
light_source { 10*<-5,10,-50>, 0.9 }
light_source { 10*<-10,10,-50>, 0.9 }
light_source { 10*<5,10,-50>, 0.9 }
light_source { 10*<10,10,-50>, 0.9 }
LeForgeronIntermerge.png


Galley

Similar to text, with formatting as traditional printing galley.

Syntax is

 galley {
 ttf FONT_NAME "string of text" <thickness, interparagraph factor, justification>, < width, interline height, left adjustment> 
 [OBJECT_MODIFIERS]
 }
 galley {
 internal FONT_NUMBER "string of text" <thickness, interparagraph factor, justification>, < width, interline height, left adjustment> 
 [OBJECT_MODIFIERS]
 }
  • ttf FONT_NAME, internal FONT_NUMBER and thickness are identical to the ones for text{}.
  • width is the desired width of the text on which to fold the text
  • interline height is the leading of the text, on the y direction. Traditional value should be -1.
  • left adjustment is the adjustement on the left margin when folding the text past the first line of a paragraph.
  • interparagraph factor is a multiplier of the interline height when a "\n" is encountered.
  • justification is 0 or less for word wrapping (do not cut words, ragged right side, width can be overruled), any positive value for letter folding (cut words, enforce the width)
  • the string of text can use \n to start a new paragraph.


LeForgeronGalley.png

justification : 1
left adjustment : +2
justification : 0
left adjustment : +2
justification : 1
left adjustment : 0
justification : 0
left adjustment : 0
justification : 1
left adjustment : -2
justification : 0
left adjustment : -2
#version 3.7;
global_settings{ charset utf8 assumed_gamma 2.2 }
#default{ finish { emission 1 diffuse 0 } }
#declare Teo="Li Europan lingues es membres del sam familie. Lor separat existentie es un myth. Por scientie, musica, sport etc, litot Europa usa li sam vocabular. Li lingues differe solmen in li grammatica, li pronunciation e li plu commun vocabules. Omnicos directe al desirabilite de un nov lingua franca: On refusa continuar payar custosi traductores.\n At solmen va esser necessi far uniform grammatica, pronunciation e plu commun paroles. Ma quande lingues coalesce, li grammatica del resultant lingue es plu simplic e regulari quam ti del coalescent lingues. Li nov lingua franca va esser plu simplic e regulari quam li existent Europanlingues. It va esser tam simplic quam Occidental in fact, it va esser Occidental. A un Angleso it va semblar un simplificat Angles, quam un skeptic Cambridge amico dit me que Occidental es. ";

#declare mar=0.181;
#declare k=30;
#declare heig=8.5;
#for(i,0,1,1)
#for(j,-2,2,2)
galley{ ttf "tahoma", Teo, <0.01,1.5,i>, <k, -1, j>
translate (heig*j+8)*y-(k+3)*i*x no_shadow
}
cylinder { -(heig*2-1)*y,2*y,mar texture { pigment { color green 1 } } translate (j)*x-(k+3)*i*x +6*z+(heig*j+8)*y }
#end

cylinder { -40*y,40*y,mar texture { pigment { color rgbf <1,1,0,0.5> } } translate -(k+3)*i*x +5*z }
cylinder { -40*y,40*y,mar texture { pigment { color rgb <0,1,1> } } translate +k*x-(k+3)*i*x +5*z }
#end

camera { orthographic
location <0,2,-30>
up y
right image_width/image_height*x
direction z
look_at 2*y
angle 100
}

#declare IS=texture { pigment { color srgb <253,248,242>/255  } } ;

plane { z,0 texture { IS } translate 10*z }

Lemon

syntax is

 lemon { 
   <Base_Point>, Base_Radius, <Cap_Point>, Cap_Radius, Inner_Radius [open]
   [OBJECTS_MODIFIERS...] 
 } 
#version 3.7;
global_settings { assumed_gamma 1.0 }

camera { location -560*z
         direction z
         up y
         right image_width*x/image_height
         angle 5
       }

#include "colors.inc"

lemon { -18*y-10*x, 0, 18*y-10*x, 0, 30 texture { pigment { color CH2RGB(30) filter 0.45 } } }
lemon { +10*x+1*y, 5, 18*y+10*x, 0, 15 texture { pigment { color CH2RGB(100) filter 0.45 } } }
lemon { -1*y+10*x, 5, -18*y+10*x, 5, 15 texture { pigment { color CH2RGB(150) filter 0.45 } } }

box { 10*z-20*x-20*y, 10*z+20*x+20*y texture { pigment { color White }}}

light_source { 10*<0,0,-20>, 0.9 }
light_source { 10*<-5,10,-50>, 0.9 }
light_source { 10*<-10,10,-50>, 0.9 }
light_source { 10*<5,10,-50>, 0.9 }
light_source { 10*<10,10,-50>, 0.9 }
LeForgeronLemon.png

Ovus, extended

syntax is

 ovus { 
   Bottom_Radius, Top_Radius [radius Inner_Radius][distance Vertical_Distance][precision Root_Tolerance]
   [OBJECTS_MODIFIERS...] 
 }
#version 3.7;
global_settings { assumed_gamma 1.0 }

camera { location -560*z
         direction z
         up y
         right image_width*x/image_height
         angle 5
       }

#include "colors.inc"

ovus { 8,0 distance 28 radius 32 sturm translate -10*x-10*y texture { pigment { color CH2RGB(30) filter 0.45 } } }
ovus { 6,6 translate 10*x+6*y sturm texture { pigment { color CH2RGB(100) filter 0.45 } } }
ovus { 6,3 radius 24 sturm translate 10*x-12*y texture { pigment { color CH2RGB(150) filter 0.45 } } }

box { 10*z-20*x-20*y, 10*z+20*x+20*y texture { pigment { color White }}}

light_source { 10*<0,0,-20>, 0.9 }
light_source { 10*<-5,10,-50>, 0.9 }
light_source { 10*<-10,10,-50>, 0.9 }
light_source { 10*<5,10,-50>, 0.9 }
light_source { 10*<10,10,-50>, 0.9 }
LeForgeronOvus.png
  • distance is the distance between the center of the two spheres, default to Bottom_Radius
  • radius is the radius of the inner circle of the connecting torus, default to twice the Bottom_Radius
  • precision is the tolerance to use for root solving of the connecting torus
  • sturm is allowed in the object modifiers