manim
manim copied to clipboard
[Bug] Adding two or more images with `ImageMobject` showing the recent image in the Scene.
Describe the bug
The ImageMobject
works perfectly fine as long as there's only one image in the Scene but as soon as another ImageMobject
(with different image) has been added in the Scene, both of the images in the screen referenced to the recently added image in the Scene.
Additional context
Here's the video that may clear the things out.
https://user-images.githubusercontent.com/41651498/229421639-118509e1-e8b4-4eb6-b27f-6d6a3de0a052.mp4
I guess the bug is in ShaderWrapper's init_textures
function. The name_to_ids
has the key "name" which is same ("Texture") for all the ImageMobject
which are added in the Scene. So, the texture id of the recently added ImageMobject
in the scene gets updated to all the previous ones.
may I try this bug
For this issue, I have an ugly solution: modify image_mobject.py,
class ImageMobject(Mobject):
shader_folder: str = "image"
shader_dtype: Sequence[Tuple[str, type, Tuple[int]]] = [
('point', np.float32, (3,)),
('im_coords', np.float32, (2,)),
('opacity', np.float32, (1,)),
]
def __init__(
self,
filename: str,
height: float = 4.0,
**kwargs
):
self.height = height
self.image_path = get_full_raster_image_path(filename)
self.image = Image.open(self.image_path)
super().__init__(texture_paths={"Texture"+str(id(self)): self.image_path}, **kwargs)
modify shader_wrapper.py
def init_program_code(self) -> None:
def get_code(name: str) -> str | None:
texture_name=""
if self.texture_paths is not None and self.shader_folder=="image":
for k in self.texture_paths:
texture_name = k
return get_shader_code_from_file(
os.path.join(self.shader_folder, f"{name}.glsl"),texture_name=texture_name
)
self.program_code: dict[str, str | None] = {
"vertex_shader": get_code("vert"),
"geometry_shader": get_code("geom"),
"fragment_shader": get_code("frag"),
}
modify shaders.py
@lru_cache()
def get_shader_code_from_file(filename: str, texture_name="") -> str | None:
if not filename:
return None
try:
filepath = find_file(
filename,
directories=[get_shader_dir(), "/"],
extensions=[],
)
except IOError:
return None
with open(filepath, "r") as f:
result = f.read()
result = re.sub(r"\s+ASPECT_RATIO\s+=\s+[\s0-9/.]+", f" ASPECT_RATIO = {ASPECT_RATIO}", result)
# To share functionality between shaders, some functions are read in
# from other files an inserted into the relevant strings before
# passing to ctx.program for compiling
# Replace "#INSERT " lines with relevant code
insertions = re.findall(r"^#INSERT .*\.glsl$", result, flags=re.MULTILINE)
for line in insertions:
inserted_code = get_shader_code_from_file(
os.path.join("inserts", line.replace("#INSERT ", ""))
)
result = result.replace(line, inserted_code)
if texture_name!="":
result = result.replace("Texture",texture_name)
return result
@germanzhu : please mention to add the field "texture_paths" to class ShaderWrapper in shader_wrapper.py.