Created
October 15, 2022 14:50
-
-
Save david-wm-sanders/a39b442ff51f26d98c0699eb7dc5de07 to your computer and use it in GitHub Desktop.
Recolour a RWR voxel model
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import xml.etree.ElementTree as XmlET | |
from pathlib import Path | |
from statistics import fmean | |
if __name__ == '__main__': | |
if (l := len(sys.argv)) != 2: | |
print(f"Error: incorrect number of parameters provided: expected 1, got {l-1}") | |
sys.exit(1) | |
xml_fp = Path(sys.argv[1]) | |
if not xml_fp.exists(): | |
print(f"Error: no file found at '{xml_fp}'") | |
sys.exit(2) | |
with xml_fp.open(mode="r", encoding="UTF-8") as f: | |
xml_str = f.read() | |
print("Loading voxel XML...") | |
mesh_xml = XmlET.fromstring(xml_str) | |
print("Discovering voxels... ", end="") | |
voxels = mesh_xml.findall("./voxels/voxel") | |
print(f"{len(voxels)} found!") | |
voxel_colours = [] | |
for voxel in voxels: | |
r, g, b = voxel.attrib["r"], voxel.attrib["g"], voxel.attrib["b"] | |
voxel_colours.append({"r": float(r), "g": float(g), "b": float(b)}) | |
# calculate average colour(s) | |
avg_r = fmean([voxel_colour["r"] for voxel_colour in voxel_colours]) | |
avg_g = fmean([voxel_colour["g"] for voxel_colour in voxel_colours]) | |
avg_b = fmean([voxel_colour["b"] for voxel_colour in voxel_colours]) | |
ar255, ag255, ab255 = round(avg_r * 255), round(avg_g * 255), round(avg_b * 255) | |
print(f"Average: R={avg_r:.3f}|{ar255}, G={avg_g:.3f}|{ag255}, B={avg_b:.3f}|{ab255}") | |
user_response = input("Target colour [R G B]: ") | |
str_colours = user_response.split() | |
if not len(str_colours) == 3: | |
print(f"Error: must specify RGB, e.g. 255 255 255") | |
sys.exit(3) | |
try: | |
tr, tg, tb = int(str_colours[0]), int(str_colours[1]), int(str_colours[2]) | |
except ValueError as e: | |
print(f"Error: must specify RGB, e.g. 255 255 255") | |
sys.exit(4) | |
if tr < 0 or tr > 255: | |
print(f"Error: R not within 0-255") | |
sys.exit(5) | |
if tg < 0 or tg > 255: | |
print(f"Error: G not within 0-255") | |
sys.exit(5) | |
if tb < 0 or tb > 255: | |
print(f"Error: B not within 0-255") | |
sys.exit(5) | |
diff_r, diff_g, diff_b = tr - ar255, tg - ag255, tb - ab255 | |
print(f"Difference: R={diff_r}, G={diff_g}, B={diff_b}") | |
drf, dgf, dbf = diff_r / 255, diff_g / 255, diff_b / 255 | |
for voxel, colour in zip(voxels, voxel_colours): | |
# calculate shifted colours, clamp within 0.0-1.0, and convert to str | |
voxel.attrib["r"] = f"{min(max(0.0, colour['r'] + drf), 1.0):.4f}" | |
voxel.attrib["g"] = f"{min(max(0.0, colour['g'] + dgf), 1.0):.4f}" | |
voxel.attrib["b"] = f"{min(max(0.0, colour['b'] + dbf), 1.0):.4f}" | |
xml_fpo = xml_fp.parent / f"{xml_fp.stem}_recolour{xml_fp.suffix}" | |
print(f"Writing recoloured voxel model to '{xml_fpo}'") | |
xml_s = XmlET.tostring(mesh_xml, encoding="unicode") | |
with xml_fpo.open(mode="w", encoding="UTF-8") as f: | |
f.write(xml_s) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment