Search code examples
pythonmanim

Moebius Strip in Manim


I'm trying to make a colored Mobius strip, but I always end up with a color difference between the beginning and the end of the strip.

Here is a MWE and the image it produces.

from manim import *

BG_COLOR = "#F7F5E7"

config.background_color = BG_COLOR


def mobius_func(u, v):
    x = (1 + v / 2 * np.cos(u / 2)) * np.cos(u)
    y = (1 + v / 2 * np.cos(u / 2)) * np.sin(u)
    z = v / 2 * np.sin(u / 2)
    return np.array((x, y, z))


class Logo(ThreeDScene):
    def construct(self):

        self.set_camera_orientation(
            phi=50 * DEGREES, theta=330 * DEGREES, run_time=2, zoom=2.2
        )

        mobius = Surface(
            mobius_func,
            u_range=[0, 2 * PI],
            v_range=[-1, 1],
            resolution=(64, 16),
        )
        mobius.set_color(RED)
        self.add(mobius)

Möbius Strip made using manim with a color difference between its beginning and its end

What causes this problem and how can I fix it ?


Solution

  • To render a Möbius strip correctly, you need a rendering engine that supports the hidden surface removal(such as z buffering) and face culling. But Manim does not supports them. So in short, you can't solve that problem.

    Your best bet will be to hack Manim like this.(Of course, it's not recommended for a long term project, because it maybe will not work on versions other than 0.17.2.)

    import numpy as np
    import manim
    
    def new_get_shaded_rgb(
        rgb: np.ndarray,
        point: np.ndarray,
        unit_normal_vect: np.ndarray,
        light_source: np.ndarray,
    ) -> np.ndarray:
        to_sun = manim.utils.space_ops.normalize(light_source - point)
        factor = 0.5 * np.dot(unit_normal_vect, to_sun) ** 3
        factor = abs(factor) # This patch will give the same color for a back or front face.
        result = rgb + factor
        return result
    manim.camera.three_d_camera.get_shaded_rgb = new_get_shaded_rgb