使用manim的起因

最近看了这位大佬将3b1b动画引擎的文章3Blue1Brown的动画引擎如何配置?,想要自己动手做一个动画视频。当然,做一个这个并不难,比如我按照大佬的教程,自己写的一个神经网络的示意视频。

from manimlib.imports import *
import os
import pyclbr

class Shapes(Scene):
    #A few simple shapes
    #Python 2.7 version runs in Python 3.7 without changes
    def construct(self):
        # 友方士兵
        circle11 = Circle(color=RED_A, radius=0.5)
        circle11.move_to(UP*3+LEFT*2)
        circle12 = Circle(color=RED_A, radius=0.5)
        circle12.move_to(LEFT*2)
        circle13 = Circle(color=RED_A, radius=0.5)
        circle13.move_to(DOWN*3+LEFT*2)
        
        # 敌方士兵
        circle21 = Circle(color=GREEN_A, radius=0.5)
        circle21.move_to(UP*2+RIGHT*2)
        circle22 = Circle(color=GREEN_A, radius=0.5)
        circle22.move_to(DOWN*2+RIGHT*2)
        
        # 攻击箭头
        arrow11 = Arrow(start=circle11,end=circle21,color=WHITE,stroke_width=3)
        arrow12 = Arrow(start=circle11,end=circle22,color=WHITE,stroke_width=3)
        arrow21 = Arrow(start=circle12,end=circle21,color=WHITE,stroke_width=3)
        arrow22 = Arrow(start=circle12,end=circle22,color=WHITE,stroke_width=3)
        arrow31 = Arrow(start=circle13,end=circle21,color=WHITE,stroke_width=3)
        arrow32 = Arrow(start=circle13,end=circle22,color=WHITE,stroke_width=3)

        # 显示过程
        self.play(ShowCreation(circle11), ShowCreation(circle12), ShowCreation(circle13))
        self.play(ShowCreation(circle21), ShowCreation(circle22))
        self.play(GrowArrow(arrow11), GrowArrow(arrow12))
        self.play(GrowArrow(arrow21), GrowArrow(arrow22))
        self.play(GrowArrow(arrow31), GrowArrow(arrow32))

if __name__ == "__main__":
    module_name = 'my_manim_test1'   #Name of current file

    for item in module_info.values():
        if item.module==module_name:
            print(item.name)
            os.system("python -m manim my_manim_test1.py %s -pl" % item.name)  #Does not play files

遇到的问题

然而在渲染文字时,我遇到了困难。按照大佬的教程,我执行代码python -m manim manim_tutorial_P37.py AddingText -pl,结果遇到了如下报错——

Traceback (most recent call last):
  File "E:\manim-3b1b\manim-master\manimlib\extract_scene.py", line 155, in main
    scene = SceneClass(**scene_kwargs)
  File "E:\manim-3b1b\manim-master\manimlib\scene\scene.py", line 53, in __init__
    self.construct()
  File "manim_tutorial_P37.py", line 64, in construct
    my_first_text=TextMobject("Writing with manim is fun")
  File "E:\manim-3b1b\manim-master\manimlib\mobject\svg\tex_mobject.py", line 148, in __init__
    self, self.arg_separator.join(tex_strings), **kwargs
  File "E:\manim-3b1b\manim-master\manimlib\mobject\svg\tex_mobject.py", line 44, in __init__
    self.template_tex_file_body
  File "E:\manim-3b1b\manim-master\manimlib\utils\tex_file_writing.py", line 19, in tex_to_svg_file
    dvi_file = tex_to_dvi(tex_file)
  File "E:\manim-3b1b\manim-master\manimlib\utils\tex_file_writing.py", line 68, in tex_to_dvi
    "See log output above or the log file: %s" % log_file)
Exception: Latex error converting to dvi. See log output above or the log file: ./media\Tex\9e7a6968d7bc54fd.log

排查错误的过程

一步一步排查原因,发现根本原因在于E:\manim-3b1b\manim-master\manimlib\utils\tex_file_writing.pytex_to_dvi函数出错了。

检查地址E:\manim-3b1b\manim-master\media\Tex的输出文件,发现9e7a6968d7bc54fd.tex确实有,但其他的啥都没有,连9e7a6968d7bc54fd.log都没有。

最开始怀疑是原装 LaTeX \LaTeX LATEX可能不行,结果装了新版本的MiKTeX,发现还是不行,MiKTeX也能在命令行中显示版本,dvisvgm版本也能显示。在网上找解决方案,基本都试了个遍,都不行。这bug差点给我整破防了,差点想放弃manim了。

然后,我尝试了下用TeXworks editor编译了下文件9e7a6968d7bc54fd.tex,发现能够正常编译出来,当然我用的是pdfLaTeX。然后在命令行里用绝对路径latex E:\manim-3b1b\manim-master\media\Tex\9e7a6968d7bc54fd.tex执行,发现也能正确输出。但cd /d E:\manim-3b1b\manim-master\后用相对路径latex ./media\Tex\9e7a6968d7bc54fd.tex编译就会显示找不到文件,这就奇了怪了。

仔细思考,md,这个错误和我上午命令行里用anaconda prompt执行python xxx.py找不到文件一个道理吗?这里的相对路径并不是相对于我的xxx.py的路径,而是相对于python.exe的路径。这个问题真是太蠢了!

仔细检查,发现原本的tex_to_dvi函数是

def tex_to_dvi(tex_file):
    result = tex_file.replace(".tex", ".dvi" if not TEX_USE_CTEX else ".xdv")
    if not os.path.exists(result):
        commands = [
            "latex",
            "-interaction=batchmode",
            "-halt-on-error",
            "-output-directory=\"{}\"".format(consts.TEX_DIR),
            "\"{}\"".format(tex_file),
            ">",
            os.devnull
        ] if not TEX_USE_CTEX else [
            "xelatex",
            "-no-pdf",
            "-interaction=batchmode",
            "-halt-on-error",
            "-output-directory=\"{}\"".format(consts.TEX_DIR),
            "\"{}\"".format(tex_file),
            ">",
            os.devnull
        ]
        exit_code = os.system(" ".join(commands))
        if exit_code != 0:
            log_file = tex_file.replace(".tex", ".log")
            raise Exception(
                ("Latex error converting to dvi. " if not TEX_USE_CTEX
                else "Xelatex error converting to xdv. ") +
                "See log output above or the log file: %s" % log_file)
    return result

问题的解决

问题就出现在commands里,"-output-directory=\"{}\"".format(consts.TEX_DIR)相当于./media\Tex\9e7a6968d7bc54fd.tex,也就是说,这是相对路径。那么**这个相对路径是相对于谁呢?**其实是相对于tex.exe的路径,而不是.py文件的相对路径。所以解决方案也呼之欲出了,把"\"{}\"".format(tex_file),改成"\""+os.path.dirname(os.path.dirname(__file__))+"\\."+tex_file+"\""就可以了。芜湖,问题解决了,准备睡觉咯。

下面附上正确的完整代码——

def tex_to_dvi(tex_file):
    result = tex_file.replace(".tex", ".dvi" if not TEX_USE_CTEX else ".xdv")
    if not os.path.exists(result):
        commands = [
            "latex",
            "-interaction=batchmode",
            "-halt-on-error",
            "-output-directory=\"{}\"".format(consts.TEX_DIR),
            "\""+os.path.dirname(os.path.dirname(__file__))+"\\."+tex_file+"\"",
            ">",
            os.devnull
        ] if not TEX_USE_CTEX else [
            "xelatex",
            "-no-pdf",
            "-interaction=batchmode",
            "-halt-on-error",
            "-output-directory=\"{}\"".format(consts.TEX_DIR),
            "\"{}\"".format(tex_file),
            ">",
            os.devnull
        ]
        exit_code = os.system(" ".join(commands))
        if exit_code != 0:
            log_file = tex_file.replace(".tex", ".log")
            raise Exception(
                ("Latex error converting to dvi. " if not TEX_USE_CTEX
                else "Xelatex error converting to xdv. ") +
                "See log output above or the log file: %s" % log_file)
    return result
Logo

NVIDIA官方入驻,分享最新的官方资源以及活动/会议信息,精选收录AI相关技术内容,欢迎大家加入社区并参与讨论。

更多推荐