Very cool! Are you running this script inside Blender, or are you using the stand alone Python interpreter? eg from the command line
Creating Scripts to Automate stuff in Blender and maybe even OpenRails
Collapse
X
-
-
You would want run it outside Blender, since it requires the WAND module package. (which needs to be installed, as well as a separate modern version of Python 3.x)
I mean, you *could* technically force it to work in Blender's version of Python.
IE; Use the "pip" package manager but specifying the target directory as the Blender Python site-packages folder to ensure the modules are accessible within the Blender application.
You need to know where your stuff lives though... in my case... typing this into the Blender Scripting console:
I get: 'C:\\Users\\willard\\AppData\\Roaming\\Blender Foundation\\Blender\\3.6\\scripts\\modules'Code:bpy.utils.user_resource("SCRIPTS",path="modules")
Example:
and you should see:Code:pip install wand --target="C:\\Users\\willard\\AppData\\Roaming\\Blender Foundation\\Blender\\3.6\\scripts\\modules"
So, now WAND is available inside Blender. (maybe?)Code:Collecting wand Using cached Wand-0.6.13-py2.py3-none-any.whl.metadata (4.0 kB) Using cached Wand-0.6.13-py2.py3-none-any.whl (143 kB) Installing collected packages: wand Successfully installed wand-0.6.13
The trick now is to make sure your "script" knows where to find the PNG files you want to convert... I leave that up to you. Mine just assumes "current" folder but a "change directory" command could be used, for example.
Well, that *should* work... need to test it in version 4.x as this technique worked for me in the past in version 3.x (Does it work with wand? Sorry, I don't know because I think WAND also has external dependencies on ImageMagick as well.)
But yeah, my thought process was to convert PNG's and TGA's to DDS with the exporter... I just haven't started on that yet.
In the past, I had imported the "pillow" library... I think WAND is going to be a problem though.Last edited by pwillard; 01-24-2025, 09:37.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
👍 1Comment
-
Hi Pete,
Very cool - "wand" - new one on me. I had tried ImageMagick in Cygwin but I couldn't get it to work - the files wouldn't display on shapes. I didn't spend a massive amount of time on it - perhaps it was a conversion issue going from Unix to Windows.
Can you edit text files in Python?
As a modeler - I don't know how you can get by without automation. When working on a model - I export it hundreds of times. Instead of trying to remember which files I changed - I do a full build of the entire model and all textures - every time. I save all my source textures as TGA to avoid compression. The Bash script I use - takes my exported model from Blender and processes everything needed - so I can simply launch ORTS and see the results after running the script.
The script performs:- Removes all old files
- Creates new DDS files from source TGA - copies to working (NVDXT)
- Fix animation issues when using 16 Key Frames (Shape Edit)
- Copies the shape to all desired units
- Edits each unit shape to point to respective texture (Shape Edit)
- Copies all shapes to working
- Makes 3D Cab
- Edits 3D Cab to point to relative texture path instead of duplicating textures (Shape Edit)
- Compresses all shapes
- Copies everything from working - to ORTS route
Regards,Code:#!/bin/bash #Acceptable Command Line Arguments - declaration () { ROUTE="ConnRiv" MSTSPATH="F:\MSTS Mini Fast\CT River\Train Simulator\Trains\Trainset" DOSCVSPATH="C:\Users\N63503\Documents\Blender\BrassRS3" CVSPATH="/cygdrive/c/N63503/Documents/Blender/BrassRS3" DOSEXPPATH="C:\Users\N63503\Documents\Blender\BrassRS3\SCO_RS3" EXPPATH="/cygdrive/c/N63503/Documents/Blender/BrassRS3/SCO_RS3" DOSRTEPATH="F:\MSTS Mini Fast\CT River\Train Simulator\Trains\Trainset\SCO_RS3" RTEPATH="/cygdrive/f/MSTS Mini Fast/CT River/Train Simulator/Trains/Trainset/SCO_RS3" NVDXT="/cygdrive/e/MSTS Tools/DDS Utilities/nvdxt.exe" NVDXT_A="/cygdrive/e/MSTS Tools/DDS Utilities/nvdxt.exe" TXT2UNI="/cygdrive/e/MSTS Tools/UTILS/txt2uni.exe" LOG=/home/N63503/tmp/ddslog.txt } createtexture () { #Remove Textures cd "${DOSCVSPATH}" rm ./*.ace 2>/dev/null rm ./*.dds 2>/dev/null cd "${DOSEXPPATH}" rm ./*.ace 2>/dev/null rm ./*.dds 2>/dev/null #Remove Shapes rm ./*.s 2>/dev/null #Make DDS echo "" echo "Process [TXT] Default" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\Default.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT 2048] Prime" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\Prime.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT 2048] PrimeFlat" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\PrimeFlat.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT 4096] Cab" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\Cab.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT EMISSIVE 1024] Gauges" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\Gauges.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT 1024] Bogie" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\Bogie.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT 1024] Wheel" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\Wheel.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT 256] Fan" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\Fan.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT REPEAT 512] MetalLight" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\MetalLight.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT REPEAT 512] MetalDark" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\MetalDark.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT REPEAT 512] MetalYellow" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\MetalYellow.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT EMISSIVE 64] NumberLight" "${NVDXT}" -box -u888 -file "${DOSCVSPATH}\NumberLight.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT ALPHA 512] Number1510" "${NVDXT_A}" -box -dxt5 -file "${DOSCVSPATH}\Number1510.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT ALPHA 512] Number1514" "${NVDXT_A}" -box -dxt5 -file "${DOSCVSPATH}\Number1514.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT ALPHA 512] Number1517" "${NVDXT_A}" -box -dxt5 -file "${DOSCVSPATH}\Number1517.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT ALPHA 512] Number1519" "${NVDXT_A}" -box -dxt5 -file "${DOSCVSPATH}\Number1519.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT ALPHA TRANS 512] Glass" "${NVDXT_A}" -box -dxt5 -file "${DOSCVSPATH}\Glass.tga" -outdir "${DOSEXPPATH}" echo "" echo "Process [TXT ALPHA TRANS 512] Glass_In" "${NVDXT_A}" -box -dxt5 -file "${DOSCVSPATH}\Glass_In.tga" -outdir "${DOSEXPPATH}" } fixshape () { echo "" echo "" echo " Fix Shape..." cd "${DOSCVSPATH}" dos2unix ./BM482A.s > /dev/null 2>/dev/null dos2unix ./BM482A_T.s > /dev/null 2>/dev/null # animation sed -- 's/animation ( 16 30/animation ( 16 60/' ./BM482A.s > ./TMPBM482A.s mv ./TMPBM482A.s ./BM482A.s } makeunit () { echo "" echo " Make Units..." cd "${DOSCVSPATH}" dos2unix ./SCO_RS3.s > /dev/null 2>/dev/null for unit in 1510 1514 1517 1519 do # Loco echo " - Building ${unit}..." sed "/image ( Number.ace )/ { s/.*/ image ( Number${unit}.ace )/ }" ./SCO_RS3.s > ./SCO_RS3_${unit}.s unix2dos ./SCO_RS3_${unit}.s > /dev/null 2>/dev/null "${TXT2UNI}" ./SCO_RS3_${unit}.s > /dev/null 2>/dev/null mv ./SCO_RS3_${unit}.s "${DOSEXPPATH}" done } copyshape () { cd "${DOSCVSPATH}" unix2dos ./SCO_RS3.s > /dev/null 2>/dev/null "${TXT2UNI}" ./SCO_RS3.s > /dev/null 2>/dev/null "${TXT2UNI}" ./RS3_CAB.s > /dev/null 2>/dev/null "${TXT2UNI}" ./Fan.s > /dev/null 2>/dev/null echo "" echo " Copy Shape Fan.s..." sleep 1 cp ./Fan.s "${DOSEXPPATH}" } make3dcab () { echo "" echo " Make 3D Cab..." cd "${DOSEXPPATH}" # Clean up the CABVIEW3D directory if it exists and recreate it rm -r ./CABVIEW3D 2>/dev/null mkdir ./CABVIEW3D cp ./*.cvf ./CABVIEW3D # Convert RS3_CAB.s to Unix format for processing dos2unix ../RS3_CAB.s > /dev/null 2>/dev/null # Edit RS3_CAB.s to prepend "../" to image paths sed -E 's/(image \( *)(.*\.ace)/\1..\/\2/' ../RS3_CAB.s > ./CABVIEW3D/RS3_CAB.s # Convert the modified file back to DOS format unix2dos ./CABVIEW3D/RS3_CAB.s > /dev/null 2>/dev/null # Ensure the file is in Unicode format "${TXT2UNI}" ./CABVIEW3D/RS3_CAB.s > /dev/null 2>/dev/null } compshape () { echo "" echo " Compress Shapes..." # Compress all files in DOSEXPPATH java TSUtil fmgr -s -c "${DOSEXPPATH}" "${DOSEXPPATH}" | tee -a ${LOG} # Compress the edited RS3_CAB.s in the CABVIEW3D directory java TSUtil fmgr -s -c "${DOSEXPPATH}/CABVIEW3D" "${DOSEXPPATH}/CABVIEW3D" | tee -a ${LOG} } copyprod () { echo "" echo " Copy Files to CT River..." cd "${MSTSPATH}" rm -r ./SCO_RS3 2>/dev/null mkdir ./SCO_RS3 cd "${DOSEXPPATH}" cp -r ./* "${MSTSPATH}"/SCO_RS3 } cleanup () { echo "" echo " Start Cleanup..." cd "${DOSCVSPATH}" "${TXT2UNI}" "${RTEPATH}" > /dev/null 2>/dev/null } ###START### declaration date > ${LOG} createtexture #fixshape makeunit copyshape make3dcab compshape copyprod cleanup date >> ${LOG} ###END####
ScottComment
-
Actually, for the past year or so I've been using Python, Yaml and Jinja2 templates to use boilerplate documents where I do variable substitutions based inside the resulting file contents using a YAML file.
Jargon noise, I know... but worth looking into
Works a treat. To be honest, Jinja2 is kind of amazing.
Last edited by pwillard; 01-24-2025, 10:48.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
Hi Pete,
Thanks.
I'll have to check that out. After I posed my question - I was like - DOH - just ask AI.
Here's how you can do it with Regular Expressions (Regex) in Python - being able to pattern match and edit text files is a powerful tool that sadly Windows never saw fit to add to CMD:
Regards,Code:import re # Read the text file with open('sample.txt', 'r') as file: data = file.read() # Perform substitutions using regular expressions data = re.sub(r'\bword_to_replace\b', 'replacement_word', data) # Write the changes back to the file with open('sample.txt', 'w') as file: file.write(data) print("Regex substitution done!")
ScottComment
-
Exactly. They assumed that all Windows users would be *scared of the command prompt* so there is no reason to develop good command line tools. Granted, way too late, they realized... gee. We need to fix it, and we got PowerShell.
And yes, you CAN use regex for subs... but the Jinja thing is a whole 'nother beast.
And... NOPE: No go on the WAND inside Blender.
Anyway... looking into options...Code:Python: Traceback (most recent call last): File "\Text", line 12, in <module> ImportError: cannot import name 'image' from 'wand' (unknown location) bpy.context.space_data.context = 'OUTPUT' bpy.ops.text.run_script() Python: Traceback (most recent call last): File "\Text", line 12, in <module> ImportError: cannot import name 'image' from 'wand' (unknown location)
Last edited by pwillard; 01-24-2025, 12:30.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
Doing this INSIDE Blender got me thinking. (and I gave up on using WAND inside Blender for now)
I did some more goofing around as I had originally thought that Pillow didn't support DDS, but that was an old memory, I guess.
It turns out it does. However, it doesn't seem to offer any compression options yet, so I'm trying with imagio in additional to Pillow, but I'm not getting the expected compression yet.
Current code, provided you get Pillow and imagio installed inside the Blender python environment.
I know it says DXT5... but the files are BIG and they shouldn't be. If I process the PNG with Paint.net, the resulting DDS file is 1.3Mb instead of 4Mb. So... huh? Seems like Paint.Net has all the answers still.Code:import bpy from PIL import Image import imageio import os def convert_png_to_dds_dxt5(input_folder, output_folder): """ Convert PNG files to DDS format with DXT5 compression using Pillow and imageio. Args: input_folder (str): Path to the folder containing PNG files. output_folder (str): Path to the folder where DDS files will be saved. """ # Ensure the output folder exists os.makedirs(output_folder, exist_ok=True) # Iterate through all files in the input folder for file_name in os.listdir(input_folder): if file_name.lower().endswith(".png"): # Full path to the input PNG file input_path = os.path.join(input_folder, file_name) # Open the image using Pillow with Image.open(input_path) as img: # Convert to RGBA (required for DXT5 compression) img = img.convert("RGBA") # Prepare the output DDS file path output_file_name = os.path.splitext(file_name)[0] + ".dds" output_path = os.path.join(output_folder, output_file_name) # Save as DDS with DXT5 compression imageio.imwrite(output_path, img, format="DDS", compression="DXT5") print(f"Converted: {input_path} -> {output_path}") # Example usage input_folder = "c:\\tmp\\new" output_folder = "c:\\tmp\\new" convert_png_to_dds_dxt5(input_folder, output_folder)
Granted, if you don't need to run inside Blender, the 'wand' option seems to work.Last edited by pwillard; 01-24-2025, 13:53.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
Pete, have you tried asking some of the different AI engines for a solution? I've had reasonable luck with Gemini for code creation, including both Python and C++...If you like what you see here at Trainsim.com, be it the discussions and knowledge in the forums, or items available in our library, I hope you'll consider a paid membership to help support keeping the site operating.... Thanks!Comment
-
Dredging an old topic, I know... but I do enjoy automating the boring stuff.
ERIC, No, I haven't really tried using Alternatives like Gemini or CoPilot. I haven't really hit any brick walls with ChatGPT that didn't turn out to be pipe dreams anyway. It's been pretty good for me.
For example: If you plan of making multiple Reporting Marks for a particular model, and you consider adopting a method used by Erick Cantu where decals are pulled from a master sheet and applied to isolated single face 'plane' objects that get applied as FreightAnims versus being a part of the master texture, then you can automate the creation of that decal sheet if its entirely based on using TTF fonts.
Lets Say I needed a decal sheet that looked like this:
decal_custom.png
Note: the generated DECAL sheet has a transparent background.
This was all done with code that was *primarily* written by AI. And it makes my life easier. The lettering is all placed at known intervals. The code can generate bounding box details for all lettering so you know where each item begins and ends, and it can optionally draw a red box around each entry, if desired.
I drove the code generation by specifying that I wanted to use a YAML-based config file and Python for each reporting mark on the sides and ends of the car. Definitions for many of the settings are also in the YAML file and not hard-coded into the Python script. You can adjust the font color to match the colors in the main texture file.
decal_custom.png
And produce a list of pixel boundaries for each entry...
Note: the initial *working* code was mine... I had ChatGPT make it flexible and more user-friendly.Code:=== SIDE LINES BOUNDARIES === [SIDE] 998 235 bbox=(5, 19, 236, 66) [SIDE] 998 375 bbox=(5, 93, 236, 140) [SIDE] 998 369 bbox=(5, 167, 236, 214) [SIDE] 998 366 bbox=(5, 241, 236, 288) [SIDE] 998 344 bbox=(5, 315, 236, 362) [SIDE] 998 343 bbox=(5, 389, 236, 436) [SIDE] 998 355 bbox=(5, 463, 236, 510) [SIDE] 998 349 bbox=(5, 537, 236, 584) [SIDE] 998 293 bbox=(5, 611, 236, 658) [SIDE] 998 292 bbox=(5, 685, 236, 732) [SIDE] 998 279 bbox=(5, 759, 236, 806) [SIDE] 998 270 bbox=(5, 833, 236, 880) === END LINES BOUNDARIES === [END ] NS 998235 top=(500, 12, 544, 35) bottom=(500, 47, 607, 69) [END ] NS 998375 top=(500, 98, 544, 121) bottom=(500, 133, 607, 155) [END ] NS 998369 top=(500, 184, 544, 207) bottom=(500, 219, 607, 241) [END ] NS 998366 top=(500, 270, 544, 293) bottom=(500, 305, 607, 327) [END ] NS 998344 top=(500, 356, 544, 379) bottom=(500, 391, 607, 413) [END ] NS 998343 top=(500, 442, 544, 465) bottom=(500, 477, 607, 499) [END ] NS 998355 top=(500, 528, 544, 551) bottom=(500, 563, 607, 585) [END ] NS 998349 top=(500, 614, 544, 637) bottom=(500, 649, 607, 671) [END ] NS 998293 top=(500, 700, 544, 723) bottom=(500, 735, 607, 757) [END ] NS 998292 top=(500, 786, 544, 809) bottom=(500, 821, 607, 843) [END ] NS 998279 top=(500, 872, 544, 895) bottom=(500, 907, 607, 929) [END ] NS 998270 top=(500, 958, 544, 981) bottom=(500, 993, 607, 1015)
Open Rails/MSTS Texturing tool for generating reporting mark decals based on TTF fonts. - pwillard/repmark
Last edited by pwillard; 10-21-2025, 12:48.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
Replying to my own thread, but here was my master plan with the previous program. It generates one or more Reporting mark entries into a PNG file. It documents the UV coordinates (boundaries) for each item it generates, and you can programmatically assign them in "UV Editing" using Python. No, I have not realized the BLENDER part of this yet, but that is the goal of exporting the JSON details from the "repmark.py" script.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
collection_tools_icon.png
And now for a silly add-on. This takes the collection setup and swapping add-on I played with and now adds a texture name swap/change feature. Have you ever wanted to make a quick change to a texture and found that references to a special PNG or TGA seem to be in multiple places? Would you like to make a quick one-click change? Ok, this add-on does that.
I do not guarantee there are no bugs in the code. Do regular backups.
A tool to help with some drudge work. Contribute to pwillard/Blender_trainsimstools development by creating an account on GitHub.
I want to point out that I am not a professional when it comes to coding. I do not have any degree or qualifications beyond a hobby interest. Comments and recommendations are welcome.
Note: Always re-check the GitHub page to see if there are updates. This code is under development, and updates happen.Last edited by pwillard; 11-07-2025, 05:03.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
More stuff along this vein...
Did you ever want to create an alpha grid pattern... like for walkways or screens? I did... and I was feeling particularly lazy.
Lets say you wanted to do this image...
Screenshot 2026-02-18 110840.png
What would you need to do? Well you need to come up with some parameters...
1) Alpha Background
2) Image size: 512px x512px
3) Tile size: 128 px
4) Grid Spacing: 10 px
5) Line width: 2px
6) Color: Black, background: Transparent
So if you feed this into a text file (YAML for those who code), you can have a script produce your results.
So... here is a quickie tool to do this.
http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
Ok, something new.
Did you ever want to get started with Blender modeling, but you open the program and BAM!, sensory overload, and you end up saying "Ok, now what am I supposed to do?"
Background:
Some of us, like me, cut our teeth on 3D Canvas/3D Crafter, which was originally the go-to tool when you fell out of love with the overly simplistic "Train Sim Modeler" or the "more complicated than Blender and short-lived GMAX". 3D Canvas was known for having some time-saving built-in extension scripting that could get you started, like building your wheel sets and base model with placeholders, called the "Train Simulator Engineer". It always bugged me that no other solution had tools like this. So it's been in the back of my mind to try emulating that feature for a long time.
image.png
So while I'm not trying to replicate that tool at the moment, I am experimenting with using a Blender ADD-ON to create "something" from just details. My goal was to generate a BOXCAR to a set of supplied dimensions, and generate a UV MAP ready to be updated with *your* textures, and then add some prebuilt assets, like Couplers and Bogies. Turns out, it was a kind of fun way to spend an afternoon and totally doable.
Screenshot 2026-06-26 194646.jpg
Right now, you need to point it to your asset files for Coupler, Wheel, and Bogie models. But that allows you to change them as needed. You can also point the tool to your Project folder that you want to work from.
In action:
Last edited by pwillard; 06-27-2026, 05:09.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
Ok, judging by the lack of interest, I won't be developing this any further. It's hard to know what people are interested in.http://www.railsimstuff.com
Just Blender now, 3DCrafter only when I have to.
Formerly The Keystone Works (All Permissions Granted)
Things I work on: https://github.com/pwillard
Comment
-
It looks interesting, but I'd be more interested in something like that for generating passenger cars.... specifying trucks, window and door locations.
Sent from my SM-S911U using Tapatalk
If you like what you see here at Trainsim.com, be it the discussions and knowledge in the forums, or items available in our library, I hope you'll consider a paid membership to help support keeping the site operating.... Thanks!Comment





Comment