Hlavní navigace

Myslíme v jazyku POV-Ray (dokončení)

Pavel Tišnovský 25. 11. 2008

Ve třicáté sedmé části seriálu o raytraceru POV-Ray bude popsán způsob volání a využití interních funkcí POV-Raye (tyto funkce jsou vložené přímo do jeho zdrojového kódu), deklarace uživatelských funkcí, vytváření maker i další možnosti programovacího jazyka, které je možné v tomto raytraceru použít.

Obsah

1. Deklarace vlastních funkcí a způsob jejich využití
2. Volání interních funkcí POV-Raye
3. První demonstrační příklad – vlastní funkce použité při tvorbě procedurálních textur
4. Druhý demonstrační příklad – interní funkce použité při tvorbě izoploch
5. Tvorba maker
6. Třetí demonstrační příklad – makra zpřehledňující zápis zdrojového kódu
7. Obsah další části seriálu

1. Deklarace vlastních funkcí a způsob jejich využití

V předchozích dvou částech tohoto seriálu jsme si řekli, že pomocí direktivy #declare a #local je možné vytvářet další identifikátory, které představují pojmenované objekty. Slovem „objekt“ je v tomto případě myšlen objekt jazyka POV-Raye, nikoli nutně geometrický objekt (těleso). Mezi použitelné typy objektů patří číslo (podporována jsou reálná čísla, přesněji řečeno jejich aproximace datovým typem double), řetězec, barva, vektor (typicky obsahující několik reálných čísel), textura, barvová mapa a v neposlední řadě i skutečný geometrický objekt, který by měl být raytracerem vykreslen. Mezi objekty, které je možné lokálně i globálně deklarovat, patří i funkce. Ty jsou představovány objektem typu function, přičemž způsob jejich zápisu se v mnohém podobá zápisu funkcí v běžných imperativních programovacích jazycích, ovšem s jednou výjimkou – většinou není nutné zapisovat názvy ani typy parametrů funkce, dokonce ani typ její návratové hodnoty, jelikož se tyto informace zjistí až v místě volání funkce.

Následuje příklad globální deklarace jednoduché funkce, ve které jsou použity dva implicitní parametry x a y (v každé funkci lze použít parametry pojmenované x, y, z, u a v bez nutnosti jejich vyjmenování v hlavičce funkce):

#declare FUNCTION1 = function
{
    (1.0+cos(5.0*x)+sin(6.0*y))
} 
povray3701

Obrázek 1: „Naprogramovaná“ scéna vykreslená raytracerem.

V případě, že funkce nepoužívá implicitní parametry x, y a z či u a v, lze jejich názvy zapsat za jméno funkce do kulatých závorek, přičemž je zapotřebí dbát na to, aby celkový počet parametrů nepřesáhl hodnotu 56. To se však v praxi stane málokdy, nehledě na to, že místo jednotlivých číselných hodnot je možné předávat i vektory:

#declare FUNCTION2 = function(x, y, k1, k2)
{
    x*k1 + y*k2 + (1-k1)*(1-k2)
} 

Uživatelsky definovaná funkce většinou vrací jednu reálnou hodnotu, v případě potřeby je však možné vytvořit i funkci vracející jiný datový typ, například barvu, lineární transformaci (ano, i ta je v POV-Rayi považována za datový typ) či řetězec. Funkce vracející barvu používá typ pigment, což je ukázáno na následujícím fragmentu kódu:

#declare foo = function
{
    pigment
    {
        color red 1
    }
} 
povray3702

Obrázek 2: Další „naprogramovaná“ scéna vykreslená raytracerem. Jejím autorem je známý umělec Truman Brown.

2. Volání interních funkcí POV-Raye

Při vytváření vlastních uživatelských funkcí je možné využít jak běžné aritmetické, logické a relační operátory (sčítání, odečítání, násobení, dělení, logický součin, součet i negaci, porovnání dvou hodnot atd.) i základní aritmetické a goniometrické funkce, tak i poměrně rozsáhlou sadu funkcí mnohem složitějších, které jsou vloženy přímo do zdrojového kódu POV-Raye (ten je mimochodem napsaný v kombinaci programovacích jazyků C a C++) a lze je volat v průběhu renderingu celé trojrozměrné scény. POV-Ray, podobně jako všechny složitější raytracery, musí obsahovat velké množství funkcí, které analyticky či v některých případech i numericky řeší výpočty průsečíků paprsků s povrchy těles, konstrukci procedurálních textur aj. Tvůrci POV-Raye se tyto již jednou napsané funkce rozhodli zveřejnit přes aplikační rozhraní a navíc k těmto funkcím přidali i funkce další (některé se však prozatím nachází jen ve stadiu testování a není zaručena kompatibilita v dalších verzích raytraceru).

povray3703

Obrázek 3: S pomocí izoploch lze v POV-Rayi vytvářet i poměrně složité objekty.

V praxi existence tohoto rozhraní znamená, že můžeme do scén vkládat například objekt typu helix ve tvaru spirály, i když pro něj neexistuje příslušné klíčové slovo – postačuje do scény vložit izoplochu, v jejíž definici se volá interní funkce POV-Raye, zde konkrétně se jedná o funkci f_helix1() či f_helix2(). Vzhledem k tomu, že každá interní funkce se volá příkazem internal(), kterému se předá identifikátor funkce (jedná se o celé kladné číslo), a který se navíc může v dalších verzích raytraceru měnit, nedoporučuje se tyto funkce volat přímo. Místo toho je vhodnější použít vkládaný soubor functions.inc, který interní funkce zpřístupní uživatelsky příjemným způsobem – pro každou funkci je zde nadeklarován vhodně pojmenovaný identifikátor a navíc je v tomto vkládaném souboru uveden i její textový popis spolu s významem všech jejich parametrů. Například výše zmíněná funkce f_helix1() je ve skutečnosti POV-Rayi známa jako interní funkce s identifikátorem 25, její pojmenování je provedeno právě v souboru functions.inc:

#declare f_helix1 = function { internal(25) }
// Parameters: x, y, z
    // Seven extra parameters required:
    // 1. Number of helixes - e.g. 2 for a double helix
    // 2. Period - is related to the number of turns per unit length
    // 3. Minor radius
    // 4. Major radius
    // 5. Shape parameter. If this is greater than 1 then the tube becomes fatter in the y direction
    // 6. Cross section type.
    // 7. Cross section rotation angle (degrees). E.g. if you choose a square cross section and rotate it by 45 degrees you get a diamond cross section. 
povray3704

Obrázek 4: Izoplocha představující povrch získaný pomocí interní funkce f_helix1().

3. První demonstrační příklad – vlastní funkce použité při tvorbě procedurálních tex­tur

V dnešním prvním demonstračním příkladu je ukázán způsob použití uživatelem definovaných funkcí při tvorbě vlastních procedurálních textur. Ve vytvořené scéně se nachází devět kvádrů, z nichž je viditelná pouze jedna strana, na kterou je nanesena uživatelsky definovaná procedurální textura. Celkem je nadeklarováno devět uživatelských funkcí představujících základ pro procedurální texturu. Připomeňme, že každá z těchto funkcí vrací reálné číslo, které je převedeno do rozsahu 0,0 až 1,0 a tato hodnota je použita při přístupu do barvové mapy (color map). Některé uživatelské funkce jsou založeny na jednoduchých výpočtech, další již používají interní funkce typu f_crackle() či f_spiral1() (tyto interní funkce tvoří základ pro nám již známé standardní procedurální textury crackle a spiral1). Specialitou je poslední uživatelská funkce FUNCTION9, jejíž vzorek je vytvořen na základě aliasu – z tohoto důvodu není vhodné, aby se scéna vykreslovala se zapnutým antialiasingem! Následuje výpis zdrojového kódu tohoto příkladu:

// ------------------------------------------------------------
// Ukázka použití procedurální textury zadané libovolnou funkcí.
// U některých procedurálních textur je využito i interních
// funkcí POV-Raye.
//
// rendering lze spustit příkazem:
//     povray +W1024 +H1024 +B100 +FN +D +Itextures.pov +Otextures.png
//
// !POZOR: scénu je nutné vykreslit se stejným horizontálním
//         i vertikálním rozlišením!
// ------------------------------------------------------------

#version 3.0
global_settings                // globální nastavení parametrů scény
{
    assumed_gamma 2.2
}

#include "colors.inc"
#include "functions.inc"       // v tomto souboru jsou uloženy odkazy
                               // na interní funkce POV-Raye

camera                         // nastavení kamery
{
    orthographic               // bez perspektivy
    location < 0, 0, -1>       // pozice kamery
    right 15*x                 // šířka a výška snímané části scény
    up 15*y
    direction z                // směr pohledu kamery (k počátku)
}

light_source                   // světelný zdroj
{
    <200, 200, -500>           // pozice
    color White                // barva
}

#declare COL1=-4.5;            // posuny objektů ve vztahu
#declare COL2= 0.0;            // k pomyslné mřížce
#declare COL3= 4.5;            // o rozměrech 3x3
#declare ROW1= 4.5;
#declare ROW2= 0.0;
#declare ROW3=-4.5;
#declare Z=0.0;

#declare COLMAP1 = color_map   // náhrada původní barvové mapy
{
    [0.02 color rgb <0.65, 0.45, 0.25> ]
    [0.06 color rgb <0.55, 0.40, 0.20> ]
    [0.10 color rgb <0.15, 0.10, 0.05> ]
    [1.00 color rgb <0.75, 0.60, 0.40> ]
}

#declare COLMAP2 = color_map   // druhá barvová mapa
{
    [0.0  color Blue]          // hodnota 0 je dolní mezí, pro kterou lze specifikovat barvu
    [0.7  color White]
    [1.0  color Red]           // hodnota 1 je naopak horní mezí
}

#declare COLMAP3 = color_map   // třetí barvová mapa
{
    [0.0  color Yellow]        // hodnota 0 je dolní mezí, pro kterou lze specifikovat barvu
    [0.7  color Black]
    [1.0  color Red]           // hodnota 1 je naopak horní mezí
}

#declare OBJECT = box
{                              // testovací objekt - jednoduchý kvádr
    <-2,-2, 0>,
    < 2, 2, 1>
}

// funkce použité při deklaraci procedurálních textur
#declare FUNCTION1 = function
{
    (1.0+cos(5*x)+sin(6*y))
}

#declare FUNCTION2 = function
{
    2*f_crackle(x,cos(x*x+y*y),z)
}

#declare FUNCTION3 = function
{
    0.5+sin(x)+y/2
}

#declare FUNCTION4 = function
{
    f_spiral2(cos(x),y,z)
}

#declare FUNCTION5 = function
{
    f_spiral1(x+sin(y), y+sin(x), z)
}

#declare FUNCTION6 = function
{
    f_spiral1(1.5*x,cos(3*y),z)
}

#declare FUNCTION7 = function
{
    0.5+0.5*sin(15*sqrt(x*x+y*y+z*z))
}

#declare FUNCTION8 = function
{
    0.5+0.5*sin(6*x)*cos(6*y)
}

// kvůli této funkci je nutné vypnout antialiasing
// - vzorek textury je tvořený právě aliasem
#declare FUNCTION9 = function
{
    50*x*x+50*y*y
}

// devět objektů potažených texturou
object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION1(x,y,z)
            }
            color_map
            {
                COLMAP1
            }
        }
    }
    translate <COL1, ROW1, Z>
}


object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION2(x,y,z)
            }
            color_map
            {
                COLMAP1
            }
        }
    }
    translate <COL2, ROW1, Z>
}

object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION3(x,y,z)
            }
            color_map
            {
                COLMAP1
            }
        }
    }
    translate <COL3, ROW1, Z>
}

object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION4(x,y,z)
            }
            color_map
            {
                COLMAP2
            }
        }
    }
    translate <COL1, ROW2, Z>
}


object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION5(x,y,z)
            }
            color_map
            {
                COLMAP2
            }
        }
    }
    translate <COL2, ROW2, Z>
}

object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION6(x,y,z)
            }
            color_map
            {
                COLMAP2
            }
        }
    }
    translate <COL3, ROW2, Z>
}

object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION7(x,y,z)
            }
            color_map
            {
                COLMAP3
            }
        }
    }
    translate <COL1, ROW3, Z>
}


object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION8(x,y,z)
            }
            color_map
            {
                COLMAP3
            }
        }
    }
    translate <COL2, ROW3, Z>
}

object
{
    OBJECT
    texture
    {
        pigment
        {
            function
            {
                FUNCTION9(x,y,z)
            }
            color_map
            {
                COLMAP3
            }
        }
    }
    translate <COL3, ROW3, Z>
}



// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray3705

Obrázek 5: Screenshot prvního demonstračního příkladu.

4. Druhý demonstrační příklad – interní funkce použité při tvorbě izoploch

Ve druhém demonstračním příkladu je ukázáno použití již výše zmíněné interní funkce pojmenované f_helix1() pro tvorbu složitějšího objektu. Tato funkce pro každý bod v prostoru (a několik dalších zadaných parametrů, kterými se specifikuje konkrétní tvar objektu) vrací jedno reálné číslo představující intenzitu (či „sílu“) v tomto bodu. Pokud se spojí všechny body se stejnou intenzitou, vznikne kýžená izoplocha, která je následně pomocí raytracingu a numerického výpočtu průsečíku světelného paprsku s izoplochou vykreslena. Tvar spirály je možné ovlivnit několika způsoby – změnou parametrů interní funkce f_helix1(), nastavením jiné prahové hodnoty (threshold) či aplikací šumové funkce na výslednou izoplochu.

Zdrojový kód dnešního druhého demonstračního příkladu má tvar:

povray3706

Obrázek 6: Screenshot druhého demonstračního příkladu.

// ------------------------------------------------------------
// Druhý demonstrační příklad na použití izoploch ve scénách
// vykreslovaných pomocí POV-Raye, přičemž pro funkci definující
// izoplochu jsou použity interní funkce POV-Raye.
//
// rendering lze spustit příkazem:
//     povray +W800 +H600 +B100 +FN +D +Iiso1.pov +Oiso1.png
// (pro náhled postačí zadat povray iso1.pov)
// ------------------------------------------------------------

#version 3.1;                            // specifikace verze POV-Raye

global_settings
{
    assumed_gamma 2.2
}

#include "colors.inc"
#include "woods.inc"
#include "functions.inc"

camera
{                                        // nastavení kamery,
    right x*image_width/image_height     // které odpovídá optice
    location  <0, 0, -8>                 // lidského oka
    look_at   <0, 0, 0>
    angle 35
}

// první světelný zdroj
light_source
{
    <500,500,-500>
    rgb 1
}

// druhý světelný zdroj
light_source
{
    <-500,500,-500>
    rgb <0.1,0.1,0.3>
    shadowless
}

// třetí světelný zdroj
light_source
{
    <3,3,-3>
    rgb <1,1,1>
    shadowless
}

// povrch plochy
#declare Solid=
texture
{                                        // vlastnosti materiálu
    pigment
    {                                    // procedurální textura
        agate
        agate_turb 0.7
    }
    finish
    {                                    // odlesky
        phong 1
    }
}



isosurface
{                                        // specifikace izoplochy
    function
    {                                    // implicitní funkce
        f_helix1(x,y,z, 2, 4, 0.3, 0.9, 0.6, 1.0, 0)
    }
    threshold 0.0                        // prahová hodnota implicitní funkce
    accuracy 1e-6                        // přesnost výpočtu
    max_gradient 2                       // maximální hodnota gradinentu
    contained_by
    {                                    // obalové těleso
        box
        {
            -2.0, 2.0
        }
    }
    texture
    {
        Solid
    }
    scale 0.9
    rotate <0, 30, -60>
}



// kvádr, do kterého je celá scéna uzavřena
box
{
    <-10,-2,-8>, < 10, 10, 8>
    texture
    {
        pigment
        {                                // šachovnicová textura
            checker
            color <0.1, 0.3, 0.4>,
            color <0.2, 0.5, 0.7>
        }
        finish
        {                                // odlesky a odrazy na povrchu
            diffuse 0.7
            reflection 0.2
        }
    }
}



// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray3707

Obrázek 7: Šumová funkce aplikovaná na původně matematicky přesnou spirálu.

5. Tvorba maker

POV-Rayi je možné kromě uživatelsky definovaných funkcí vytvářet i takzvaná makra, která mohou nahradit procedury. Makra jsou (na rozdíl od výše zmíněných funkcí) zpracovávána již preprocesorem v průběhu načítání zdrojového kódu scény a následné konstrukce její interní reprezentace. POV-Rayovská makra se syntakticky i sémanticky do značné míry podobají makrům používaným v programovacích jazycích C a C++, ovšem s tím rozdílem, že se při jejich vytváření využívá direktiva #macro a nikoli #define. Makro nemusí ležet na jednom logickém řádku, protože je ukončeno direktivou #end, podobně jako mnohé další konstrukce preprocesoru. Jednou vytvořené makro je možné odstranit nám již známou direktivou #undef, dokonce je možné – opět podobně jako v céčku a C++ – používat direktivy #ifdef a #ifndef pro rozhodnutí, zda je makro (či nějaký další pojmenovaný objekt) již deklarován či nikoli.

povray3708

Obrázek 8: Screenshot třetího demonstračního příkladu – začátek animace.

6. Třetí demonstrační příklad – makra zpřehledňující zápis zdrojového kódu

Využití maker pro zpřehlednění zápisu složitějšího tělesa je ukázáno v dnešním posledním demonstračním příkladu. Trojrozměrné těleso zobrazené na osmém a devátém obrázku je tvořeno složitou implicitní plochou, jejímž základem je spirála složená ze série dvou bodových prvků kostry propojených prvkem úsečkovým. Konstrukce jedné „tyčinky“ je představována makrem WholeRod, v němž se volají další tři makra FirstBall, SecondBall a Connection. Všimněte si, že s pomocí maker lze jednoduše kombinovat programové konstrukce s deklarativním zápisem geometrických objektů a jejich vlastností. Výslednou animaci uloženou ve formátu MPEG-1 (použity jsou I, PB snímky, protože rozdíly mezi dvěma sousedními framy jsou minimální) s rozlišením 320×240 pixelů je možné získat po kliku na tento odkaz. Celá animace obsahuje 500 snímků, doba jejího trvání je tedy cca 20 sekund.

// ------------------------------------------------------------
// Třetí demonstrační příklad - použití maker při tvorbě scén
// vykreslovaných pomocí POV-Raye.
//
// Založeno na souboru BlobLoop.pov, jehož autorem je:
// Eduard Schwan (1.10.1995)
// ------------------------------------------------------------

// specifikace verze POV-Raye
#version 3.1

// globální nastavení parametrů scény
global_settings
{
    assumed_gamma 1.0
}

// nastavení kamery
camera
{
    location  <0, 10, -8>
    direction 1*z
    look_at   <0, 0, 0>
}


// první světelný zdroj
light_source
{
    <30, 20, -30>
    color rgb 1
}

// druhý světelný zdroj
light_source
{
    <-10, 30, -30>
    color rgb 0.5
}

// tmavé pozadí scény
background
{
    color rgb <0.0, 0.1, 0.2>
}

// podlaha pokrytá texturou mramoru
plane
{
    y, -0.1
    texture
    {
        pigment                          // textura mramoru
        {
            marble
            turbulence 0.5 omega 0.7 rotate -40*y scale 6
            color_map
            {
                [0.50 color rgb 1.0]
                [0.57 color rgb 0.8]
                [0.60 color rgb <0.9,0.8,0.7>]
                [0.63 color rgb 1.0]
            }
        }
        finish {ambient 0.2 reflection 0.3}
    }
}

// celé těleso vytvořené z metaballs
#macro WholeRod(counter, height, increment, numTwists)
    FirstBall(counter, height, increment, numTwists)
    SecondBall(counter, height, increment, numTwists)
    Connection(counter, height, increment, numTwists)
#end

// první část tělesa
#macro FirstBall(counter, height, increment, numTwists)
    sphere
    {
        <-5*(1-counter), counter*height, 0>, increment*30, 2
        rotate counter*numTwists*y
        texture
        {
            // barva závisí na poloze prvku kostry
            pigment
            {
                color rgb <counter, 0, 1>
            }
            finish
            {
                ambient 0.2 specular 0.6 phong 1.0 reflection 0.3 roughness 0.01
            }
        }
    }
#end

// druhá část tělesa
#macro SecondBall(counter, height, increment, numTwists)
    sphere
    {
        < 5*(1-counter), counter*height, 0>, increment*30, 2
        rotate counter*numTwists*y
        texture
        {
            // barva závisí na poloze prvku kostry
            pigment
            {
                color rgb <1, 0, counter>
            }
            finish
            {
                ambient 0.2 specular 0.6 phong 1.0 reflection 0.3 roughness 0.01
            }
        }
    }
#end

// spojnice mezi první a druhou částí
#macro Connection(counter, height, increment, numTwists)
    cylinder
    {
      <-5*(1-counter), counter*height, 0>,
      < 5*(1-counter), counter*height, 0>,
      increment*20,
      2
      texture
      {
          pigment
          {
              color rgb counter/2
          }
          finish
          {
              ambient 0.2 specular 0.6 phong 1.0 reflection 0.3 roughness 0.01
          }
      }
      rotate counter*numTwists*y
    }
#end

// počet iterací - rozměr tělesa
#local NumIterations = 40

// parametry tělesa
#local Increment     = 1.0/NumIterations
#local NumTwists     = 360*3*(0.5+clock)
#local Height        = 5

// těleso vytvořené z metaballs
blob
{
    threshold 0.5

    // čítač programové smyčky
    #local Counter = 0.001
    #while (Counter<=1.0)
        WholeRod(Counter, Height, Increment, NumTwists)
        #local Counter=Counter+Increment
    #end

    rotate -30*y
}



// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray3709

Obrázek 9: Screenshot třetího demonstračního příkladu – konec animace.

7. Obsah další části seriálu

V následující části seriálu o raytraceru POV-Ray se začneme zabývat tvorbou složitějších typů textur. Řekneme si, jak lze vytvářet textury složené z několika vrstev, jakým způsobem je možné ovlivnit způsob výpočtu procedurálních textur a další pokročilejší techniky, které POV-Ray v této oblasti nabízí.

Našli jste v článku chybu?

26. 11. 2008 9:31

atarist (neregistrovaný)
To by vlastně znamenalo, že když se amplituda šumové funkce "přežene", tak se spirála může rozpadnout na více částí, že?

26. 11. 2008 9:30

atarist (neregistrovaný)
Jakým způsobem je možné vymodelovat objekt na sedmém obrázku? Pochopil jsem to správně tak, že se k interní funkci představující spirálu "přičte" šumová funkce, tj. f_noise3d()?
Podnikatel.cz: Nejenom EET, začaly platit další zákony

Nejenom EET, začaly platit další zákony

Podnikatel.cz: Chtějte údaje k dani z nemovitostí do mailu

Chtějte údaje k dani z nemovitostí do mailu

DigiZone.cz: ČRa DVB-T2 ověřeno má i Sharp

ČRa DVB-T2 ověřeno má i Sharp

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Vitalia.cz: Pravda o přibírání na zimu

Pravda o přibírání na zimu

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

Podnikatel.cz: Babiš: E-shopy z EET možná vyjmeme

Babiš: E-shopy z EET možná vyjmeme

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

Vitalia.cz: Dáte si jahody s plísní?

Dáte si jahody s plísní?

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

Vitalia.cz: Baletky propagují zdravotní superpostel

Baletky propagují zdravotní superpostel

Vitalia.cz: Co pomáhá dítěti při zácpě?

Co pomáhá dítěti při zácpě?

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

DigiZone.cz: ČRa DVB-T2 ověřeno: Hisense a Sencor

ČRa DVB-T2 ověřeno: Hisense a Sencor

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky