
Nắp che pump Lithophane lục giác (Hex) cho Cooler Master AIO
Remix of Mẫu STEP Pump AIO Elite Liquid Series By CoolerMaster
- Downloads
- 0
- Likes
- 1
- Views
- 99
- Remixes
- 0
- Comments
- 0
Files 7 194.2 MB
- CoolerMaster_1778170163.stlSTL · 29.4 MB
- Ice_1778170166.stlSTL · 29.4 MB
- Kcd2_1778170168.stlSTL · 29.4 MB
- Prusa_1778170170.stlSTL · 29.4 MB
Make a variant with AI
Build another version of this model.
Details
- Model ID
- #376162
- Category
- Dụng Cụ Tiện Ích
- Published
- Tags
- case
- computer
- cooling
- lithophane
- coolermaster
- abdeckung
- modding
- watercooling
- aio
- carcasa
- pcmod
- boitier
- impression
- pumpe
- bomba
- gehause
- technik
- impresion
- ordenador
- technique
- ordinateur
- pompe
- custompc
- kuehler
- cubierta
- druckteil
- wasserkuehlung
- stampa
- refroidissement
- raffreddamento
- copertura
- pompa
- refrigeracion
- pumpcover
- personalizacion
- personnalisation
- couverture
- personalizzazione
- tecnologia
- anpassung
- tecnica
- pcbau
Description
This is a hex-style pump cover for Cooler Master AIOs with a slot for custom lithophane inserts.
The cover features a clean cutout designed to hold a lithophane plate.
A Python script is included to generate lithophanes that fit precisely into this opening.
The workflow is simple: generate your image, print it, and insert it into the cover.
Lithophane Generator (Python)
You can generate the lithophane using Thonny and the provided Python script.
Required libraries:
-
PIL
-
numpy
-
numpy-stl
Script:
# Spring 2026 – Hydrolith Generator (Hex Smooth Version)
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image, ImageOps, ImageDraw, ImageTk
import numpy as np
from stl import mesh
import os
#********************** HEX PARAMETERS **********************************#
SIDE_LENGTH_MM = 28.28434
WIDTH_MM = 2 * SIDE_LENGTH_MM
HEIGHT_MM = np.sqrt(3) * SIDE_LENGTH_MM
BORDER_WIDTH_MM = 2.0
#********************** SMOOTH HEX MASK *********************************#
def hex_mask_mm(w_px, h_px, resolution, side_length_mm, scale=1.0, upscale=16):
up_w = w_px * upscale
up_h = h_px * upscale
mask_img = Image.new("L", (up_w, up_h), 0)
draw = ImageDraw.Draw(mask_img)
cx, cy = up_w / 2, up_h / 2
s_px = (side_length_mm * scale) / resolution * upscale
R = s_px
# Flat-top Hexagon
points = [
(
cx + R * np.cos(i * np.pi/3),
cy + R * np.sin(i * np.pi/3)
)
for i in range(6)
]
draw.polygon(points, fill=255)
# Anti-aliased downscale
mask = mask_img.resize((w_px, h_px), resample=Image.LANCZOS)
return np.array(mask) / 255.0 # smooth mask
#********************** Lithophane generation ***************************#
def create_lithophane(image_path, output_path, min_thick, max_thick, resolution, border_height, invert=False, progress_callback=None):
px_per_mm = 1 / resolution
size_px = (int(WIDTH_MM * px_per_mm), int(HEIGHT_MM * px_per_mm))
img_raw = Image.open(image_path).convert("L")
img = ImageOps.fit(img_raw, size_px, method=Image.LANCZOS, centering=(0.5, 0.5))
img = img.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
grayscale = np.asarray(img) / 255.0
if invert:
grayscale = 1.0 - grayscale
height_map = min_thick + (1.0 - grayscale) * (max_thick - min_thick)
h, w = height_map.shape
outer_mask = hex_mask_mm(w, h, resolution, SIDE_LENGTH_MM, scale=1.0)
inner_scale = 1.0 - (BORDER_WIDTH_MM / SIDE_LENGTH_MM)
inner_mask = hex_mask_mm(w, h, resolution, SIDE_LENGTH_MM, scale=inner_scale)
mask = outer_mask
rim_mask = outer_mask * (1.0 - inner_mask)
# weiche Kante → physisch glatter Übergang
height_map = min_thick + (height_map - min_thick) * mask
vertices = []
faces = []
vertex_index = {}
def get_index(x, y, ztype):
key = (x, y, ztype)
if key not in vertex_index:
if ztype == 'top':
z = height_map[y, x]
elif ztype == 'rim':
z = border_height
else:
z = 0.0
vertices.append([x * resolution, y * resolution, z])
vertex_index[key] = len(vertices) - 1
return vertex_index[key]
threshold = 0.5
for y in range(h - 1):
for x in range(w - 1):
if not (mask[y, x] > threshold and
mask[y, x+1] > threshold and
mask[y+1, x] > threshold and
mask[y+1, x+1] > threshold):
continue
def ztype(ix, iy):
return 'rim' if rim_mask[iy, ix] > threshold else 'top'
i0 = get_index(x, y, ztype(x, y))
i1 = get_index(x + 1, y, ztype(x + 1, y))
i2 = get_index(x, y + 1, ztype(x, y + 1))
i3 = get_index(x + 1, y + 1, ztype(x + 1, y + 1))
b0 = get_index(x, y, 'bottom')
b1 = get_index(x + 1, y, 'bottom')
b2 = get_index(x, y + 1, 'bottom')
b3 = get_index(x + 1, y + 1, 'bottom')
faces += [[i0, i1, i2], [i1, i3, i2]]
faces += [[b2, b1, b0], [b2, b3, b1]]
faces += [
[i0, b0, i1], [i1, b0, b1],
[i1, b1, i3], [i3, b1, b3],
[i3, b3, i2], [i2, b3, b2],
[i2, b2, i0], [i0, b2, b0]
]
if progress_callback and y % 10 == 0:
progress_callback(y / (h - 1))
vertices_np = np.array(vertices)
faces_np = np.array(faces)
litho = mesh.Mesh(np.zeros(faces_np.shape[0], dtype=mesh.Mesh.dtype))
for i, f in enumerate(faces_np):
for j in range(3):
litho.vectors[i][j] = vertices_np[f[j], :]
litho.save(output_path)
#****************************** GUI **************************************#
class LithopaneApp:
def init(self, root):
self.root = root
self.root.title("Hydrolith Hex Smooth")
self.image_path = ""
tk.Button(root, text="Select Image", command=self.load_image).grid(row=0, column=0, columnspan=2, pady=10)
self.entries = {}
labels = [
("Min. Thickness (mm)", "0.8"),
("Max. Thickness (mm)", "3.2"),
("Resolution (mm/px)", "0.3"),
("Border Height (mm)", "2.0")
]
for i, (label, default) in enumerate(labels, start=1):
tk.Label(root, text=label).grid(row=i, column=0, sticky="e")
entry = tk.Entry(root)
entry.insert(0, default)
entry.grid(row=i, column=1)
self.entries[label] = entry
self.invert_var = tk.BooleanVar()
tk.Checkbutton(root, text="Invert colors (negative)", variable=self.invert_var).grid(row=5, column=0, columnspan=2)
self.status = tk.Label(root, text="", fg="blue")
self.status.grid(row=6, column=0, sticky="e")
self.progress = ttk.Progressbar(root, orient="horizontal", length=200, mode="determinate")
self.progress.grid(row=6, column=1, sticky="w")
tk.Button(root, text="Export STL", command=self.export_stl).grid(row=7, column=0, columnspan=2, pady=10)
tk.Button(root, text="Show Preview", command=self.show_preview).grid(row=8, column=0, columnspan=2)
def load_image(self):
file_path = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg *.png *.bmp")])
if file_path:
self.image_path = file_path
self.status.config(text=os.path.basename(file_path))
def update_progress(self, fraction):
self.progress["value"] = int(fraction * 100)
self.root.update_idletasks()
def export_stl(self):
if not self.image_path:
messagebox.showwarning("Warning", "Please select an image first.")
return
try:
min_thick = float(self.entries["Min. Thickness (mm)"].get())
max_thick = float(self.entries["Max. Thickness (mm)"].get())
resolution = float(self.entries["Resolution (mm/px)"].get())
border_height = float(self.entries["Border Height (mm)"].get())
except ValueError:
messagebox.showerror("Error", "Invalid input.")
return
output_path = filedialog.asksaveasfilename(defaultextension=".stl")
if not output_path:
return
create_lithophane(
self.image_path,
output_path,
min_thick,
max_thick,
resolution,
border_height,
invert=self.invert_var.get(),
progress_callback=self.update_progress
)
self.status.config(text="Done.")
def show_preview(self):
if not self.image_path:
return
resolution = float(self.entries["Resolution (mm/px)"].get())
px_per_mm = 1 / resolution
size_px = (int(WIDTH_MM * px_per_mm), int(HEIGHT_MM * px_per_mm))
img = ImageOps.fit(Image.open(self.image_path).convert("L"), size_px)
grayscale = np.asarray(img) / 255.0
mask = hex_mask_mm(size_px[0], size_px[1], resolution, SIDE_LENGTH_MM)
preview = Image.fromarray((grayscale * mask * 255).astype(np.uint8))
preview = preview.resize((300, 300))
win = tk.Toplevel(self.root)
tk_img = ImageTk.PhotoImage(preview)
tk.Label(win, image=tk_img).pack()
win.image = tk_img
# Run
if name == "main":
root = tk.Tk()
app = LithopaneApp(root)
root.mainloop()
For best Lithopane results:
-
Use 100% infill
-
Use the lowest possible layer height
This improves light diffusion and overall image clarity.
Print spec
- Formats
- stl
- Model files
- 7
- Total size
- 194.2 MB
- Largest file
- 29.4 MB












