reanimate-0.4.2.0: src/Reanimate/Blender.hs
{-# LANGUAGE OverloadedStrings #-}
{-|
[Blender](https://www.blender.org/) is a free and open-source 3D graphics toolkit.
It is usually used through a graphical user-interface but can also be
scripted via Python. These Blender scripts can access 100% of Blender's
functionality and offer a convenient way of coding 3D effects.
Running Blender can be time-consuming but heavy caching means scripts
are only run when they change.
Blender cheatsheet:
> # To generate with a transparent background, set film_transparent = True:
> bpy.context.scene.render.film_transparent = True
>
> # Filmic is great for photorealism but bad for animations.
> # If you want your textures to keep their exact color values,
> # set the view_transform to 'Standard':
> bpy.context.scene.view_settings.view_transform = 'Standard'
>
> # Blender's default render engine is 'EEVEE', fast but not a raytracer.
> # To switch to raytracing, set the engine to 'CYCLES':
> bpy.context.scene.render.engine = 'CYCLES'
>
> # Rendering at full resolution can be slow. When developing, try
> # decreasing the resolution_percentage for faster renders.
> bpy.context.scene.render.resolution_percentage = 10
>
> # The resolution of the final image are set by resolution_x and resolution_y:
> bpy.context.scene.render.resolution_x = 320
> bpy.context.scene.render.resolution_y = 180
-}
module Reanimate.Blender
( blender
, blender'
) where
import Data.Hashable
import Data.Text (Text)
import qualified Data.Text.IO as T
import Graphics.SvgTree (Tree (..))
import Reanimate.Animation
import Reanimate.Cache
import Reanimate.Constants
import Reanimate.Misc
import Reanimate.Parameters
import Reanimate.Raster
import Reanimate.Svg.Constructors
import System.FilePath (replaceExtension, (<.>))
import System.IO.Unsafe (unsafePerformIO)
-- | Run a Blender script and embed the resulting image file. The
-- image will be scaled to fit the screen exactly (assuming a default
-- canvas layout). Note that Blender resolution defaults to 1920x1080
-- but can be changed in the script code.
blender :: Text -> SVG
blender script =
unsafePerformIO $ mkBlenderImage script
-- | Generate Blender image as a separate PNG file. Can be embedded with
-- `mkImage`.
blender' :: Text -> FilePath
blender' script =
unsafePerformIO $ mkBlenderImage' script
mkBlenderImage :: Text -> IO Tree
mkBlenderImage script | pNoExternals = pure $ mkText script
mkBlenderImage script =
mkImage screenWidth screenHeight <$> mkBlenderImage' script
mkBlenderImage' :: Text -> IO FilePath
mkBlenderImage' _ | pNoExternals = pure "/blender/has/been/disabled"
mkBlenderImage' script = cacheFile template $ \target -> do
exec <- requireExecutable "blender"
let py_file = replaceExtension target "py"
T.writeFile py_file script
runCmd exec [ "--background","--render-format", "PNG"
, "--python-exit-code", "1"
, "--render-output", target, "--python", py_file]
where
template = encodeInt (hash script) <.> "png"