Improve povray examples.

Former-commit-id: b1101fe5b3a7b9bec0b6b92f303d42be8114d128
This commit is contained in:
David Himmelstrup 2019-12-05 17:17:22 +08:00
commit 8333d3d4f1
6 changed files with 370 additions and 39 deletions

View file

@ -241,3 +241,18 @@ This file is auto-generated by docs/render_all.sh. DO NOT EDIT.
<br/><hr><br/> <br/><hr><br/>
## tut_glue_povray
<details>
<summary>View tut_glue_povray.hs</summary>
<pre><code class="haskell">
{!examples/tut_glue_povray.hs!}
</code></pre>
</details>
<br/>
<video width="640" height="360" autoplay loop>
<source src="https://github.com/Lemmih/reanimate/raw/master/docs/rendered/tut_glue_povray.mp4">
</video>
<br/><hr><br/>

View file

@ -4,7 +4,8 @@ ROOT=`stack path --project-root`
EXAMPLES='boundingbox colormaps goo latex_basic latex_color latex_draw EXAMPLES='boundingbox colormaps goo latex_basic latex_color latex_draw
latex_wheel raster sphere blender_default_cube latex_wheel raster sphere blender_default_cube
tut_glue_svg tut_glue_animate tut_glue_keyframe tut_glue_fourier tut_glue_svg tut_glue_animate tut_glue_keyframe tut_glue_fourier
tut_glue_physics tut_glue_latex' tut_glue_physics tut_glue_latex tut_glue_povray
tut_glue_povray_ortho'
WIDTH=640 WIDTH=640
HEIGHT=$((WIDTH*9/16)) HEIGHT=$((WIDTH*9/16))

View file

@ -82,7 +82,7 @@ The following examples shows how something as seemingly complicated as fourier s
<source src="https://github.com/Lemmih/reanimate/raw/master/docs/rendered/tut_glue_fourier.mp4"> <source src="https://github.com/Lemmih/reanimate/raw/master/docs/rendered/tut_glue_fourier.mp4">
</video> </video>
Scripting in Haskell also gives access to the extensive body of code libraries. There are Haskell libraries for syntax highlighting, font manipulation, and much, much more. In the spirit of being a batteries-included framework, Reanimate ships with a built-in 2D physics library, called Chipmunk2D. The example below demonstrates how SVG shapes can be generated with LaTeX and then nearly effortlessly used in a physics simulation. Scripting in Haskell also gives access to the extensive body of code libraries. There are Haskell libraries for syntax highlighting, font manipulation, and much, much more. In the spirit of being a batteries-included framework, Reanimate ships with a built-in 2D physics library, called Chipmunk2D. The example below demonstrates how SVG shapes can be used nearly effortlessly in a physics simulation.
<details> <details>
<summary>Toggle source code.</summary> <summary>Toggle source code.</summary>
@ -120,7 +120,34 @@ The resulting SVGs can be manipulated just like any other. The below examples il
## Pillar III: povray ## Pillar III: povray
TODO: Draw text and animate shapes, zoom out so it looks like a piece of paper (still animated), draw circle, fade in rotating sphere. TODO: Draw text and animate shapes, zoom out so it looks like a piece of paper (still animated).
<details>
<summary>Toggle source code.</summary>
<pre><code class="haskell">
{!examples/tut_glue_povray.hs!}
</code></pre>
</details>
<br/>
<video width="640" height="360" autoplay loop>
<source src="../rendered/tut_glue_povray.mp4">
<source src="https://github.com/Lemmih/reanimate/raw/master/docs/rendered/tut_glue_povray.mp4">
</video>
TODO: Talk about orthographic projection. Draw circle, fade in rotating sphere.
<details>
<summary>Toggle source code.</summary>
<pre><code class="haskell">
{!examples/tut_glue_povray_ortho.hs!}
</code></pre>
</details>
<br/>
<video width="640" height="360" autoplay loop>
<source src="../rendered/tut_glue_povray_ortho.mp4">
<source src="https://github.com/Lemmih/reanimate/raw/master/docs/rendered/tut_glue_povray_ortho.mp4">
</video>
## Pillar IV: Blender ## Pillar IV: Blender

View file

@ -16,7 +16,12 @@ import System.Random
import System.Random.Shuffle import System.Random.Shuffle
main :: IO () main :: IO ()
main = reanimate $ parA bg $ sceneAnimation $ do main = reanimate $ parA bg latexExample
where
bg = animate $ const $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)
latexExample :: Animation
latexExample = sceneAnimation $ do
-- Draw equation -- Draw equation
play $ drawAnimation strokedSvg play $ drawAnimation strokedSvg
sprites <- forM glyphs $ \(fn, _, elt) -> sprites <- forM glyphs $ \(fn, _, elt) ->
@ -41,7 +46,6 @@ main = reanimate $ parA bg $ sceneAnimation $ do
withStrokeColor "black" svg withStrokeColor "black" svg
svg = lowerTransformations $ simplify $ scale 2 $ center $ svg = lowerTransformations $ simplify $ scale 2 $ center $
latexAlign "\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}" latexAlign "\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}"
bg = animate $ const $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)
shuffleList lst = shuffle' lst (length lst) (mkStdGen 0xdeadbeef) shuffleList lst = shuffle' lst (length lst) (mkStdGen 0xdeadbeef)
highlightE :: Effect highlightE :: Effect

View file

@ -5,80 +5,83 @@
module Main (main) where module Main (main) where
import Reanimate import Reanimate
import Reanimate.Scene
import Reanimate.Animation
import Reanimate.Povray import Reanimate.Povray
import Reanimate.Raster import Reanimate.Raster
import Reanimate.Effect
import Data.String.Here import Data.String.Here
import Graphics.SvgTree hiding (Text)
import Data.Text (Text) import Data.Text (Text)
import Codec.Picture
import System.Random
import System.Random.Shuffle
import Control.Lens ((^.))
import Data.Monoid
import Control.Monad
import Codec.Picture.Types
main :: IO () main :: IO ()
main = reanimate $ mkAnimation 10 $ \t -> main = reanimate $ parA bg $ sceneAnimation $ do
let s = fromToS 0 4 t in zPos <- newVar 0
let rot = fromToS 0 (360) t in xRot <- newVar 0
mkGroup zRot <- newVar 0
[ mkBackground "black" s <- newSprite $ do
, povraySlow [] (script (svgAsPngFile (texture $ oscillateS t)) s rot) transZ <- freezeVar zPos
-- , texture $ oscillateS t getX <- freezeVar xRot
] getZ <- freezeVar zRot
return $ \real_t dur t ->
povraySlow [] $
script (svgAsPngFile (texture (t/dur))) (transZ real_t) (getX real_t) (getZ real_t)
wait 2
tweenVar zPos 9 (\t v -> fromToS v 8 (t/9))
tweenVar xRot 9 (\t v -> fromToS v 360 $ curveS 2 (t/9))
tweenVar zRot 9 (\t v -> fromToS v 360 $ curveS 2 (t/9))
wait 10
tweenVar zPos 2 (\t v -> fromToS v 0 $ curveS 3 (t/2))
wait 2
where where
bg = animate $ const $ mkBackgroundPixel $ PixelRGBA8 252 252 252 0xFF
texture :: Double -> SVG texture :: Double -> SVG
texture t = mkGroup texture t = mkGroup
[ checker 10 10 [ checker 10 10
, translate (screenWidth/2) 0 $ , frameAt (t*duration latexExample) latexExample ]
translate (-screenWidth*t) 0 $
withFillColor "red" $ mkCircle 3 ]
script :: FilePath -> Double -> Double -> Text script :: FilePath -> Double -> Double -> Double -> Text
script png s rot = [iTrim| script png transZ rotX rotZ = [iTrim|
//EXAMPLE OF SPHERE
//Files with predefined colors and textures
#include "colors.inc" #include "colors.inc"
#include "glass.inc"
#include "golds.inc"
#include "metals.inc"
#include "stones.inc"
#include "woods.inc"
#include "shapes3.inc"
//Place the camera //Place the camera
camera { camera {
perspective perspective
//location <0,0,-9-${s*2}>
location <0,0,-9> location <0,0,-9>
look_at <0,0,0> look_at <0,0,0>
up y up y
right x*16/9 right x*16/9
} }
//Ambient light to "brighten up" darker pictures //Ambient light to "brighten up" darker pictures
global_settings { ambient_light White*3 } global_settings { ambient_light White*3 }
//Set a background color //Set a background color
//background { color White }
//background { color rgbt <0.1, 0, 0, 0> } // red
background { color rgbt <0, 0, 0, 1> } // transparent background { color rgbt <0, 0, 0, 1> } // transparent
polygon { polygon {
4, 4,
//<-9, -4.5>, <-9, 4.5>, <9, 4.5>, <9, -4.5>
<0, 0>, <0, 1>, <1, 1>, <1, 0> <0, 0>, <0, 1>, <1, 1>, <1, 0>
texture { texture {
//pigment{ color rgb <0,1,0> }
pigment{ pigment{
image_map{ png ${png} } image_map{ png ${png} }
} }
} }
translate <-1/2,-1/2> translate <-1/2,-1/2>
scale <16,9> scale <16,9>
rotate <0,${rot},${rot}> rotate <0,${rotX},${rotZ}>
translate <0,0,${s*2}> translate <0,0,${transZ}>
} }
|]
|]
checker :: Int -> Int -> SVG checker :: Int -> Int -> SVG
checker w h = checker w h =
@ -105,3 +108,81 @@ checker w h =
stepY = screenHeight/fromIntegral h stepY = screenHeight/fromIntegral h
offsetX = screenWidth/2 offsetX = screenWidth/2
offsetY = screenHeight/2 offsetY = screenHeight/2
-----------------------------------
-- COPIED FROM tut_glue_latex.hs --
latexExample :: Animation
latexExample = sceneAnimation $ do
-- Draw equation
play $ drawAnimation strokedSvg
sprites <- forM glyphs $ \(fn, _, elt) ->
newSpriteA $ animate $ const $ fn elt
-- Yoink each glyph
forM_ (reverse sprites) $ \sprite -> do
spriteE sprite (overBeginning 1 $ aroundCenterE $ highlightE)
wait 0.5
-- Flash glyphs randomly with color
forM_ (shuffleList (sprites++sprites)) $ \sprite -> do
spriteE sprite (overBeginning 0.5 $ aroundCenterE $ flashE)
wait 0.1
wait 0.5
mapM_ destroySprite sprites
-- Undraw equations
play $ drawAnimation' (Just 0xdeadbeef) 1 0.1 strokedSvg
# reverseA
where
glyphs = svgGlyphs svg
strokedSvg =
withStrokeWidth (defaultStrokeWidth*0.5) $
withStrokeColor "black" svg
svg = lowerTransformations $ simplify $ scale 2 $ center $
latexAlign "\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}"
shuffleList lst = shuffle' lst (length lst) (mkStdGen 0xdeadbeef)
highlightE :: Effect
highlightE d t =
scale (1 + bellS 2 (t/d)*0.5) . rotate (wiggleS (t/d) * 20)
flashE :: Effect
flashE d t =
withStrokeColor "black" .
withStrokeWidth (defaultStrokeWidth*0.5*bellS 2 (t/d)) .
withFillColorPixel (promotePixel $ turbo (t/d))
-- s-curve, sin, s-curve
wiggleS :: Signal
wiggleS t
| t < 0.25 = curveS 2 (t*4)
| t < 0.75 = sin ((t-0.25)*2*pi+pi/2)
| otherwise = curveS 2 ((t-0.75)*4)-1
--
drawAnimation :: SVG -> Animation
drawAnimation = drawAnimation' Nothing 0.5 0.3
drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation
drawAnimation' mbSeed fillDur step svg = sceneAnimation $ do
forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do
let sWidth =
case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of
Just (Num d) -> d
_ -> defaultStrokeWidth
fork $ do
wait (n*step)
play $ mapA fn $ (animate (\t -> withFillOpacity 0 $ partialSvg t tree)
# applyE (overEnding fillDur $ fadeLineOutE sWidth))
fork $ do
wait (n*step+(1-fillDur))
newSprite $ do
return $ \_real_t _d t ->
withStrokeWidth 0 $ fn $ withFillOpacity (min 1 $ t/fillDur) tree
where
shuf lst =
case mbSeed of
Nothing -> lst
Just seed -> shuffle' lst (length lst) (mkStdGen seed)

203
examples/tut_glue_povray_ortho.hs Executable file
View file

@ -0,0 +1,203 @@
#!/usr/bin/env stack
-- stack runghc --package reanimate
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Main (main) where
import Reanimate
import Reanimate.Scene
import Reanimate.Animation
import Reanimate.Povray
import Reanimate.Raster
import Data.String.Here
import Data.Text (Text)
import Codec.Picture
import Reanimate.Effect
import Reanimate.Scene
import System.Random
import System.Random.Shuffle
import Graphics.SvgTree hiding (Text)
import Control.Lens ((^.))
import Control.Monad
import Codec.Picture.Types
import Data.Monoid
main :: IO ()
main = reanimate $ parA bg $ sceneAnimation $ do
xRot <- newVar (-30)
yRot <- newVar 180
zRot <- newVar 0
s <- newSprite $ do
getX <- freezeVar xRot
getY <- freezeVar yRot
getZ <- freezeVar zRot
return $ \real_t dur t ->
povraySlow [] $
script (svgAsPngFile (texture (t/dur))) (getX real_t) (getY real_t) (getZ real_t)
wait 2
let tDuration = 20
tweenVar yRot tDuration (\t v -> fromToS v (v+180) $ curveS 2 (t/tDuration))
tweenVar xRot (tDuration/2) (\t v -> fromToS v (v+60) $ curveS 2 (t/(tDuration/2)))
fork $ do
wait (tDuration/2)
tweenVar xRot (tDuration/2) (\t v -> fromToS v (v-60) $ curveS 2 (t/(tDuration/2)))
--tweenVar zRot 9 (\t v -> fromToS v 360 $ curveS 2 (t/9))
wait tDuration
wait 2
--tweenVar zPos 2 (\t v -> fromToS v 0 $ curveS 3 (t/2))
--wait 2
where
bg = animate $ const $ mkBackgroundPixel $ PixelRGBA8 252 252 252 0xFF
texture :: Double -> SVG
texture t = mkGroup
[ checker 10 10
, frameAt (t*duration latexExample) latexExample
]
script :: FilePath -> Double -> Double -> Double -> Text
script png rotX rotY rotZ = [iTrim|
//Files with predefined colors and textures
#include "colors.inc"
#include "shapes3.inc"
//Place the camera
camera {
orthographic
location <0,0,-10>
look_at <0,0,0>
up <0,9,0>
right <16,0,0>
}
//Ambient light to "brighten up" darker pictures
global_settings { ambient_light White*3 }
//Set a background color
//background { color White }
//background { color rgbt <0.1, 0, 0, 0> } // red
background { color rgbt <0, 0, 0, 1> } // transparent
//Sphere with specified center point and radius
sphere {
<0,0,0>, 4
texture {
uv_mapping pigment{
image_map{ png ${png} }
}
}
rotate <0,${rotY},${rotZ}>
rotate <${rotX},0,0>
}
|]
checker :: Int -> Int -> SVG
checker w h =
withFillColor "white" $
withStrokeColor "white" $
withStrokeWidth 0.1 $
mkGroup
[ withStrokeWidth 0 $
withFillOpacity 0.7 $ mkBackground "blue"
, mkGroup
[ translate (stepX*x-offsetX + stepX/2) 0 $
mkLine (0, -screenHeight/2*0.9) (0, screenHeight/2*0.9)
| x <- map fromIntegral [0..w-1]
]
,
mkGroup
[ translate 0 (stepY*y-offsetY) $
mkLine (-screenWidth/2, 0) (screenWidth/2, 0)
| y <- map fromIntegral [0..h]
]
]
where
stepX = screenWidth/fromIntegral w
stepY = screenHeight/fromIntegral h
offsetX = screenWidth/2
offsetY = screenHeight/2
-----------------------------------
-- COPIED FROM tut_glue_latex.hs --
latexExample :: Animation
latexExample = sceneAnimation $ do
-- Draw equation
play $ drawAnimation strokedSvg
sprites <- forM glyphs $ \(fn, _, elt) ->
newSpriteA $ animate $ const $ fn elt
-- Yoink each glyph
forM_ (reverse sprites) $ \sprite -> do
spriteE sprite (overBeginning 1 $ aroundCenterE $ highlightE)
wait 0.5
-- Flash glyphs randomly with color
forM_ (shuffleList (sprites++sprites)) $ \sprite -> do
spriteE sprite (overBeginning 0.5 $ aroundCenterE $ flashE)
wait 0.1
wait 0.5
mapM_ destroySprite sprites
-- Undraw equations
play $ drawAnimation' (Just 0xdeadbeef) 1 0.1 strokedSvg
# reverseA
where
glyphs = svgGlyphs svg
strokedSvg =
withStrokeWidth (defaultStrokeWidth*0.5) $
withStrokeColor "black" svg
svg = lowerTransformations $ simplify $ scale 2 $ center $
latexAlign "\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}"
bg = animate $ const $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)
shuffleList lst = shuffle' lst (length lst) (mkStdGen 0xdeadbeef)
highlightE :: Effect
highlightE d t =
scale (1 + bellS 2 (t/d)*0.5) . rotate (wiggleS (t/d) * 20)
flashE :: Effect
flashE d t =
withStrokeColor "black" .
withStrokeWidth (defaultStrokeWidth*0.5*bellS 2 (t/d)) .
withFillColorPixel (promotePixel $ turbo (t/d))
-- s-curve, sin, s-curve
wiggleS :: Signal
wiggleS t
| t < 0.25 = curveS 2 (t*4)
| t < 0.75 = sin ((t-0.25)*2*pi+pi/2)
| otherwise = curveS 2 ((t-0.75)*4)-1
--
drawAnimation :: SVG -> Animation
drawAnimation = drawAnimation' Nothing 0.5 0.3
drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation
drawAnimation' mbSeed fillDur step svg = sceneAnimation $ do
forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do
let sWidth =
case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of
Just (Num d) -> d
_ -> defaultStrokeWidth
fork $ do
wait (n*step)
play $ mapA fn $ (animate (\t -> withFillOpacity 0 $ partialSvg t tree)
# applyE (overEnding fillDur $ fadeLineOutE sWidth))
fork $ do
wait (n*step+(1-fillDur))
newSprite $ do
return $ \_real_t _d t ->
withStrokeWidth 0 $ fn $ withFillOpacity (min 1 $ t/fillDur) tree
where
shuf lst =
case mbSeed of
Nothing -> lst
Just seed -> shuffle' lst (length lst) (mkStdGen seed)