sprockets frosted donut medals buildings Rubik's Cube Nidaros Cathedral Tongue Sandwich A:M Composite
sprockets
Recent Posts | Unread Content | Previous Banner Topics
Jump to content
Hash, Inc. - Animation:Master

All Activity

This stream auto-updates

  1. Past hour
  2. Mind if I ask how you created/what your process was for creating the Play-Doh/Clay effect on the models? It looks great and the animation really captures the claymation/stop-motion style!
  3. Today
  4. At today's LAT I was unsuccessful in making a Selection Filter. This post shows How to make a Selection Filter. Occasionally, it doesn't work. If not, select the bad filter's tab, choose "Remove Filter" in that small triangle menu... and try again! @Dylan Perry @Ganthofer @Roger @ChuckGram
  5. Could only find "upload images" so I'll post it here and please let me know the proper way to do this and if you can play this video. VLC was used to convert it. This particular video had a lot of help from robcat (the glowing threads) DWfinalTitleC.mp4
  6. At the end of Live Answer Time today we watched a cat climb a fence... Check out the compressed anticipation pose. Check out the full extension of the legs before he leaves the ground.
  7. Hi Dylan, I think that is 3AM Sunday Morning, Melbourne Time. Ouch!
  8. I'd like to come and join you guys but I can't seem to figure out what time it will be in Melbourne Australia. I'm getting different results depending on what converter I use! Can anyone help me figure it out?
  9. You'll be mesmerized by the answers you get when you bring your A:M questions to Live Answer Time at Noon CDT, Saturday, August 16 2025! Felix the Cat animator Otto Messmer was born on this day in 1892. "Feline Follies," the first Felix cartoon.
  10. Yesterday
  11. Attached is my Batman scene file with decals, easier then looking through any DVDs Batman.zip
  12. Hi Robert, Just looked at the date my original model was created and says October 12th 1999. Don't recall who at Hash I was in communications with (might of been Steve Sappington) they probably wanted to render an image for shows and stuff.
  13. So Hash commissioned this Batman... what did they do with him? Is he on a DVD?
  14. The more thorough September 5 , 2020 video uses Auto Assign at 43:53 Note that the "head" problem discussed at 1:01:37 will probably not be a problem for you. It seems to have only happened to me.
  15. My fav view of him so far.
  16. Understood, I have to redo the rig from scratch using this TSM2 and version 15 if I remember right. You also used an "auto assign" at one point I think that made things quicker and that's why I could use the video of that LAT to study more closely but I don't think it's available yet. I'll keep checking to see when it is. thanks for responding robcat.
  17. Darker coloured suit and some colour corrections in PS.
  18. Looks good, now we just need a cigarette dangling out the corner of the mouth.
  19. A rendering of Bats, finally arms down.
  20. Last week
  21. problem 1 - the only bone you should be rotating in a smartskin window is the bone that smartskin is for. The smartskin window says it is for "LBicepDynamic", so moving "LBicep" is going to be trouble unless there is a great reason to do it. problem 2- you're still using this rig that has a zillion extra bones and constraints added on top of the geometry bones. When you are making smartskin you should be using a version of the model that is geometry bones only... geometry bones that are easy to move. problem 3 - I don't think this "COGS" rig was designed with smartskin in mind. Is there a place in the instructions where it says "do your smartskins now"? If there is, I don't think this stage of the model is it. problem 4 - You should be using TSM2. You'd be done already. TSM2 gives you a version of your model with just geometry bones for you to do your CP weighting and smartskinning and no constraints yet making things fly around crazy.
  22. Is this just on my machine er whut? Please try to rotate the Lbicep bone in the Smartskin window, either with the manipulator or scrubbing the Y axis in the PWS. On my machine it goes WACKO rotating spastically in large increments and the bone is way off. Even tried saving the model to disk & importing it into a new Prj. but no difference. Recently had similart problems but was resolved with AVG anti virus but it's not working now, so any help appreciated. SuitCoat3.prj
  23. Two more slight variations Rocky44_000.mp4 @John Bigboote wanted a bigger shape on Ro-cky Rocky44x_000.mp4
  24. It's spline controllers... see? Rocky42_000.mp4
  25. Thanks Robert! He has a basic rig for posing, If I ever do anything more with him he would need some major smart skinning
  26. That's a great looking Batman, Michael. Is he rigged, too?
  27. Some results from recent C++ exercise regarding file data manipulation. Using this image as input: Here "edge detection" has been done. Every pixel in the original was tested to see if its red, green, or blue values were different from its neighboring pixels beyond a certain threshold. If so, a white pixel was plotted in the new image. If not, a black pixel is plotted. Here the image has been rotated. Every pixel in the output image is populated by the values of a pixel that is x degrees from it, around a center point. If that x degree rotation is looking at a position that is off the original frame, a black pixel is plotted.
  28. Has anyone ever tried using AM under Crossover, either on Mac or Linux? I'm contemplating trying running it on Linux under Crossover and just wondered if anyone else had already tried this.
  29. Earlier
  30. The updated Watchfolder script: import os import time import shutil import keyboard import subprocess import re from datetime import datetime import configparser import sys # === DEFAULT CONFIG === DEFAULTS = { "watch_dir": "F:/renderfolder", "ffmpeg_path": "ffmpeg", "framerate": "24", "timeout": "5", "video_basename": "video", "max_runtime_minutes": "0", "reset_timeout_on_video": "false", # GIF options "make_gif": "true", "gif_max_seconds": "6", # 0 = full video "gif_width": "320", "gif_fps": "12", "gif_suffix": "_thumb" } def get_exe_dir(): if getattr(sys, 'frozen', False): return os.path.dirname(sys.executable) else: return os.path.dirname(os.path.abspath(__file__)) INI_FILE = os.path.join(get_exe_dir(), "watchfolder.ini") # ----------------- Config ----------------- def load_config(): config = configparser.ConfigParser(inline_comment_prefixes=("#", ";")) if not os.path.exists(INI_FILE): # write a friendly ini with comment lines (not inline) config["settings"] = DEFAULTS with open(INI_FILE, "w") as f: f.write( "[settings]\n" "watch_dir = F:/renderfolder\n" "ffmpeg_path = ffmpeg\n" "framerate = 24\n" "timeout = 5\n" "video_basename = video\n" "max_runtime_minutes = 0\n" "reset_timeout_on_video = false\n" "# GIF settings\n" "make_gif = true\n" "gif_max_seconds = 6\n" "gif_width = 320\n" "gif_fps = 12\n" "gif_suffix = _thumb\n" ) print(f"[i] Created default {INI_FILE}") else: config.read(INI_FILE) if "settings" not in config: config["settings"] = {} for key, val in DEFAULTS.items(): if key not in config["settings"]: config["settings"][key] = val return config["settings"] # ----------------- Helpers ----------------- def get_png_files(watch_dir): return sorted([f for f in os.listdir(watch_dir) if f.lower().endswith('.png')]) def get_next_video_filename(watch_dir, basename): count = 1 while True: candidate = f"{basename}_{count:04d}.mp4" if not os.path.exists(os.path.join(watch_dir, candidate)): return candidate count += 1 def guess_pattern(filename): match = re.search(r"([^.]+)\.(\d+)\.png$", filename) if match: prefix, digits = match.groups() return f"{prefix}.%0{len(digits)}d.png" return None # ----------------- Core Actions ----------------- def convert_sequence_to_mp4(watch_dir, first_file, ffmpeg_path, framerate, video_basename): """Convert PNG sequence to MP4. Returns absolute path to MP4 on success, else None.""" pattern = guess_pattern(first_file) if not pattern: print(f"[!] Could not determine pattern from {first_file}") return None output_name = get_next_video_filename(watch_dir, video_basename) output_path = os.path.join(watch_dir, output_name) print(f"[+] Converting to MP4: {output_name}") try: subprocess.run([ ffmpeg_path, "-y", "-framerate", str(framerate), "-i", pattern, "-c:v", "libx264", "-pix_fmt", "yuv420p", output_path ], cwd=watch_dir, check=True) print(f"[✓] Video saved as: {output_name}") return output_path except subprocess.CalledProcessError as e: print(f"[!] FFmpeg failed: {e}") return None def move_sequence_to_archive(watch_dir, png_files): now = datetime.now().strftime("%Y%m%d_%H%M%S") archive_dir = os.path.join(watch_dir, "processed", now) os.makedirs(archive_dir, exist_ok=True) for f in png_files: shutil.move(os.path.join(watch_dir, f), os.path.join(archive_dir, f)) print(f"[→] Moved PNGs to: {archive_dir}") return archive_dir def make_gif_thumbnail(video_path, ffmpeg_path, gif_width, gif_fps, gif_max_seconds, gif_suffix): """ Create a small animated GIF from MP4 using palettegen/paletteuse for quality. Saves next to the MP4: e.g., video_0001_thumb.gif """ base, _ = os.path.splitext(video_path) gif_path = f"{base}{gif_suffix}.gif" palette_path = f"{base}_palette.png" # Build common filter chain: fps + scale + split for palette vf_chain = f"fps={gif_fps},scale={gif_width}:-1:flags=lanczos" # Optional duration clamp (0 = full length) duration_args = [] if gif_max_seconds > 0: duration_args = ["-t", str(gif_max_seconds)] try: # 1) Palette generation subprocess.run([ ffmpeg_path, "-y", "-i", video_path, *duration_args, "-vf", f"{vf_chain},palettegen=stats_mode=diff", palette_path ], check=True) # 2) Palette use subprocess.run([ ffmpeg_path, "-y", "-i", video_path, *duration_args, "-i", palette_path, "-lavfi", f"{vf_chain}[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5", gif_path ], check=True) # Clean up palette try: os.remove(palette_path) except OSError: pass print(f"[✓] GIF thumbnail created: {os.path.basename(gif_path)}") return gif_path except subprocess.CalledProcessError as e: print(f"[!] GIF creation failed: {e}") return None # ----------------- Monitor Loop ----------------- def monitor(settings): watch_dir = settings["watch_dir"] ffmpeg_path = settings["ffmpeg_path"] framerate = int(settings.get("framerate", 24)) timeout = int(settings.get("timeout", 5)) video_basename = settings["video_basename"] max_runtime = int(settings.get("max_runtime_minutes", "0").strip()) * 60 reset_on_video = settings.get("reset_timeout_on_video", "false").lower() == "true" make_gif = settings.get("make_gif", "true").lower() == "true" gif_max_seconds = int(settings.get("gif_max_seconds", "6").strip()) gif_width = int(settings.get("gif_width", "320").strip()) gif_fps = int(settings.get("gif_fps", "12").strip()) gif_suffix = settings.get("gif_suffix", "_thumb") print(f"👁️ Monitoring folder: {watch_dir}") print(f"[i] FFmpeg: {ffmpeg_path}, timeout: {timeout}s, framerate: {framerate}fps") if max_runtime > 0: print(f"[i] Will auto-exit after {max_runtime // 60} minutes (unless reset)") if make_gif: print(f"[i] GIF: width={gif_width}, fps={gif_fps}, max_seconds={gif_max_seconds} (suffix='{gif_suffix}')") start_time = time.time() previous_files = set(get_png_files(watch_dir)) last_change_time = time.time() while True: # Escape to exit if keyboard.is_pressed("esc"): print("[✋] Escape key pressed. Exiting.") break time.sleep(1) # Auto-exit if timer exceeded if max_runtime > 0 and (time.time() - start_time > max_runtime): print("[!] Max runtime reached. Exiting.") break current_files = set(get_png_files(watch_dir)) if current_files != previous_files: previous_files = current_files last_change_time = time.time() continue if current_files and (time.time() - last_change_time > timeout): png_files = sorted(current_files) print(f"[⏳] Sequence complete: {len(png_files)} files") # 1) Make MP4 mp4_path = convert_sequence_to_mp4(watch_dir, png_files[0], ffmpeg_path, framerate, video_basename) # 2) Move PNGs move_sequence_to_archive(watch_dir, png_files) # 3) Make GIF thumbnail (optional) if mp4_path and make_gif: make_gif_thumbnail( video_path=mp4_path, ffmpeg_path=ffmpeg_path, gif_width=gif_width, gif_fps=gif_fps, gif_max_seconds=gif_max_seconds, gif_suffix=gif_suffix ) previous_files = set() last_change_time = time.time() if reset_on_video: print("[i] Timer reset after video creation.") start_time = time.time() print("[✓] Monitoring stopped.") # ----------------- Entry ----------------- if __name__ == "__main__": try: settings = load_config() monitor(settings) except KeyboardInterrupt: print("\n[✓] Monitoring stopped by user.") The updated watchfolder.ini settings file: [settings] watch_dir = F:/renderfolder ffmpeg_path = ffmpeg framerate = 24 timeout = 5 video_basename = video max_runtime_minutes = 30 reset_timeout_on_video = true make_gif = true gif_max_seconds = 6 ; 0 = full length gif_width = 320 ; scaled width, height auto-preserved gif_fps = 12 ; frames per second in GIF gif_suffix = _thumb ; appended before .gif
  1. Load more activity
×
×
  • Create New...