layout: true class: animated fadeIn middle numbers .footnote[ `IPS-PROD` - N. Dubray - ENSIIE - 2024 - [:book:](../index.html) ] --- # POV-Ray .hcenter.w40[] ## History * very old project (~1980) * maintained by **The POV-Team** * name means "Persistence of Vision Ray Tracer" ## Key points * ray-tracer * Turing-complete scene description language * procedural textures * radiosity .block[ * Repository: [https://github.com/POV-Ray/povray](https://github.com/POV-Ray/povray) * Website: [http://www.povray.org](http://www.povray.org) * License: `AGPLv3` ] --- # Ray-tracing ## What is ray-tracing ? :arrow_right: a method to generate nearly photo-realistic images by modeling light rays. ## Key points * very good reproduction of shadows, reflections, refractions, scattering, etc... * **very high computational cost** * can easily use **parallelization** * :arrow_right: **real-time ray-tracing** is coming ! ## Main types of ray-tracing * eye-based (historical) * light-based * bidirectional path tracing * photon mapping (for caustics, global illumination...) * etc... --- # POV-Ray - General ## Workflow 1. describe the scene in a file 2. let POV-Ray interpret the file and generate an image ## Object types * POV-Ray default objects * user-defined objects ## Object properties * how it deflects / reflects light * texture / material / color * etc... --- # POV-Ray - Example .row[ .column.w48[ ## .hcenter[`[example_00.pov]`] ```pov #include "colors.inc" background { color White } camera { location <0, 2, -3> look_at <0, 1, 2> } sphere { <0, 1, 2>, 2 texture { pigment { color Red } } } light_source { <2, 4, -3> color White} ``` ] .column.w48.middle[ ## .hcenter[Shell session] ```shell $ povray +A0.0001 -W800 -H600 +P +Q11 example_00.pov ``` ] ] .hcenter.w40.shadow[] --- # POV-Ray - Source code ## Syntax * **very close from `C`** * case-sensitive * whitespaces are ignored * **order of objects** is ignored (but not order of properties) * comments use `/* ... */` and `//` like `C` * include other files with `#include "..."` ## Vectors `
` * can refer to a point in 2D-space `
` * can refer to a point in 3D-space `
` * can refer to a color `rgb
` with `\(0\le \{r,g,b\} \le 1\)` * can refer to a transparent color `rgbf
` with `\(0\le \{r,g,b,f\} \le 1\)` * can refer to a normal vector `
` --- # POV-Ray - Initial scene .row[ .column.w48.middle[ ```pov camera { location <1,4,-5> look_at <0,1,0> angle 45 } ``` ] .column.w48[ ## Camera :arrow_right: defines the "eye" of the observer ] ] .row[ .column.w48.middle[ ```pov light_source { <-2,7,-3> color rgb <1,1,1> } ``` ] .column.w48[ ## Light :arrow_right: emits some light ] ] .row[ .column.w48.middle[ ```pov background { rgb <1,1,1> // rgbf <1,1,1,0> } ``` ] .column.w48[ ## Background :arrow_right: defines the default color of rays ] ] --- # POV-Ray - Plane .row[ .column.w40.middle[ ```pov object { plane { <0,1,0> // normal axis 0 // where does the plane cut the axis pigment { checker // checker pattern color rgb <0.7,0.7,0.8> // light gray color rgb <0.5,0.5,0.5> // dark gray scale 2 } } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Sphere .row[ .column.w40.middle[ ```pov object { sphere { <0,1,0>, 1 // center, radius } pigment { color rgb <0,1,0> // pure green } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Torus .row[ .column.w40.middle[ ```pov object { torus { 0.8, 0.2 // big radius, small radius } pigment { color rgb <0,0,1> // pure blue } finish { phong 1.0 reflection 0.2 } rotate <90,0,0> // rotation translate <0,1,0> // translation } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Box .row[ .column.w40.middle[ ```pov object { box { <-1,0,-1>, <1,2,1> // corners } pigment { color rgb <1,0,0> // pure red } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Cylinder .row[ .column.w40.middle[ ```pov object { cylinder { <0,0,0> // 1st center <0,2,0> // 2nd center 1 // radius } pigment { color rgb <1,1,0> // pure yellow } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Cone .row[ .column.w40.middle[ ```pov object { cone { <0,0,0> // 1st center 1 // 1st radius <0,2,0> // 2nd center 0.1 // 2nd radius } pigment { color rgb <1,0,1> // pure magenta } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Lathe .row[ .column.w40.middle[ ```pov object { lathe { cubic_spline // type of spline 6 // number of points <1.0,0> // -+ <1.0,0> // | <1.0,2> // | spline <0.3,2> // | <0.3,0> // | <0.3,0> // -+ } pigment { color rgb <0,1,1> // pure cyan } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Prism .row[ .column.w40.middle[ ```pov object { prism { linear_spline // type of spline 0, 2 // origin, height 10 // number of points <-1,-1> // -+ <-1,1> // | <1,1> // | outer spline <1,-1> // | <-1,-1> // -+ <-0.8,-0.8> // -+ <-0.8,0.8> // | <0.8,0.8> // | inner spline <0.8,-0.8> // | <-0.8,-0.8> // -+ } pigment { color rgb <1,0,0> // pure red } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Height field .row[ .column.w40.middle[ ```pov #declare fn_Hills = function { pigment { bumps warp { turbulence 0.5 } scale 0.2 } } object { height_field { function 16, 16 { fn_Hills (x, y, z).red } } pigment { gradient y color_map { [0.0 color rgb <1,1,1>] [0.5 color rgb <1,1,1>] [1.0 color rgb <1,0,0>] } } finish { phong 1.0 reflection 0.2 } translate <-0.5, -0.5, -0.5> scale <2, 0.5, 2> translate <0,1,0> } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Height field .row[ .column.w40.middle[ ```pov #declare fn_Hills = function { pigment { bumps warp { turbulence 0.5 } scale 0.2 } } object { height_field { * function 100, 100 { fn_Hills (x, y, z).red } * smooth } pigment { gradient y color_map { [0.0 color rgb <1,1,1>] [0.5 color rgb <1,1,1>] [1.0 color rgb <1,0,0>] } } finish { phong 1.0 reflection 0.2 } translate <-0.5, -0.5, -0.5> scale <2, 0.5, 2> translate <0,1,0> } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Blob .row[ .column.w40.middle[ ```pov object { blob { threshold 0.6 // isovalue sphere { <.75, 0, 0> // center 1 // radius 1 // strength } sphere { <-.375, .64952, 0>, 1, 1 } sphere { <-.375, -.64952, 0>, 1, 1 } rotate <90,0,0> translate <0,1,0> scale 1.2 } pigment { color rgb <0,1,0> // pure green } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Text .row[ .column.w40.middle[ ```pov object { text { ttf "timrom.ttf" "ENSIIE" // font 0.3 // thickness 0 // offset translate <-1.6,-0.35,-0.15> scale 1.0 translate <0,1,0> } pigment { agate // pattern type color_map { [0.00 color rgb <1,0,0>] [0.25 color rgb <1,1,0>] [0.50 color rgb <0,1,0>] [0.75 color rgb <0,1,1>] [1.00 color rgb <0,0,1>] } scale 2.0 } finish { phong 1.0 reflection 0.2 } } }``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Transparency .row[ .column.w40.middle[ ```pov object { text { ttf "timrom.ttf" "ENSIIE" // font 0.3 // thickness 0 // offset translate <-1.6,-0.35,-0.15> scale 1.0 translate <0,1,0> } pigment { * rgbf <1,0,0,0.9> } finish { phong 1.0 reflection 0.2 * ambient 0.1 * diffuse 0.5 * specular 0.5 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Union of objects .row[ .column.w40.middle[ ```pov object { union { box { <-1,0,-1>, <1,2,1> } sphere { <0,2,0>, 1.0 } scale 0.7 } pigment { color rgb <0,1,0> // pure green } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Intersection of objects .row[ .column.w40.middle[ ```pov object { intersection { box { <-1,0,-1>, <1,2,1> } sphere { <0,2,0>, 1.0 } scale 0.7 } pigment { color rgb <0,0,1> // pure blue } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Difference of objects .row[ .column.w40.middle[ ```pov object { difference { box { <-1,0,-1>, <1,2,1> } sphere { <0,2,0>, 1.0 } scale 0.7 } pigment { color rgb <1,0,0> // pure red } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Merge objects .row[ .column.w40.middle[ ```pov object { merge { box { <-1,0,-1>, <1,2,1> } sphere { <0,2,0>, 1.0 } scale 0.7 } pigment { color rgb <1,1,0> // pure yellow } finish { phong 1.0 reflection 0.2 } } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Union / Merge comparison .row[ .column.w48.middle[ ## .hcenter[Union] .hcenter.shadow[] ] .column.w48.middle[ ## .hcenter[Merge] .hcenter.shadow[] ] ] --- # POV-Ray - Density .row[ .column.w40.middle[ ```pov object { box { <-1,-1,-1>, <1,1,1> * hollow } pigment { color rgbf <1,1,1,1> } interior { media { emission 0.75 scattering {1, 0.5} * density { spherical color_map { [0.0 rgb <0,0,0.5>] [0.5 rgb <0.8, 0.8, 0.4>] [1.0 rgb <1,1,1>] } } } } translate <0,1,0> * translate <0,0.001,0> } ``` ] .column.w55.middle[ .hcenter.shadow[] ] ] --- # POV-Ray - Nuclear Local Density .hcenter.shadow.w80[] --- # POV-Ray - `visu.pov` :arrow_right: file available [here](../examples/povray/visu.pov). This scene uses a density file called `example.df3`. ```pov [...] box { <0,0,0><1,1,1> hollow pigment { rgbf 1 } interior { media { emission 0.7 absorption 1.0 intervals 10 density { * density_file df3 "example.df3" scale
interpolate INTERPOLATE color_map { [0.0 rgb <0.0,0.0,0.0>] [0.1 rgb <0.0,0.0,2.0>] [1.0 rgb <1.0,1.0,1.0>] } } } } scale <10,10,20> translate <-5,-5,-10> rotate y*90 } [...] ``` --- # POV-Ray - `df3` format ## Reference [POV-Ray df3 format](http://povray.org/documentation/3.7.0/r3_4.html#r3_4_7_1_8_1). .block[ ## Header The df3 format consists of a 6 byte header of three 16-bit integers with high order byte first. These three values give the x,y,z size of the data in pixels (or more appropriately called voxels). ## Data The header is followed by x*y*z unsigned integer bytes of data with a resolution of 8, 16 or 32 bit. The data are written with high order byte first (big-endian). The resolution of the data is determined by the size of the df3-file. That is, if the file is twice (minus header, of course) as long as an 8 bit file then it is assumed to contain 16 bit ints and if it is four times as long 32 bit ints. ] --- # POV-Ray - `df3` writer ```C++ std::string cubeToDf3(const arma::cube &m) { std::stringstream ss(std::stringstream::out | std::stringstream::binary); int nx = m.n_rows; int ny = m.n_cols; int nz = m.n_slices; ss.put(nx >> 8); ss.put(nx & 0xff); ss.put(ny >> 8); ss.put(ny & 0xff); ss.put(nz >> 8); ss.put(nz & 0xff); double theMin = 0.0; double theMax = m.max(); for (uint k = 0; k < m.n_slices; k++) { for (uint j = 0; j < m.n_cols; j++) { for (uint i = 0; i < m.n_rows; i++) { uint v = 255 * (fabs(m(i, j, k)) - theMin) / (theMax - theMin); ss.put(v); } } } return ss.str(); } ``` where `m` is an `arma::cube` representing the density to be plotted. **Mandatory dimensions for `m`**: .hcenter[ | Axis | x | y | z | | :--: | :----: | :----: | :----: | | min | -10 fm | -10 fm | -20 fm | | max | 10 fm | 10 fm | 20 fm | | nbp | 32 | 32 | 64 | ] --- # POV-Ray - Conclusions .hcenter.shadow.w60[] :+: rather powerful ray-tracer :+: very easy to generate scenes :+: very easy to automate mass-production of renderings :+: good introduction to ray-tracers :warning: not a modeler :warning: may seem old-school at some points :arrow_right: **My advice:** use it as your first ray-tracer, then switch to **Blender**, especially if you need a modeler.