Mao Yidi
Close-up of a keyboard seen at an angle, with grey keycaps and a few red, blue, yellow, green, purple and orange accent keys.

Powershell Snippets

Shell Scripts

Manipulating Assets as a technical artist.

Improve Assets Naming

From the several game jams, I found group members tend to have bad naming habits, which is common phenomenon among students.

Bad naming could lead to unexpected error in game engine, so I wrote this script to find out all the poorly named assets in our project.

function List-FilesWithCJKCharacters {
    Get-ChildItem -Recurse | Where-Object { $_.Name -match "[\p{IsCJKUnifiedIdeographs}]"} | ForEach-Object {
        Write-Host (Resolve-Path $_.FullName -Relative)
    }
}

function List-FilesWithSpacesInName {
    Get-ChildItem -Recurse | Where-Object { $_.Name -match " " } | ForEach-Object {
        Write-Host (Resolve-Path $_.FullName -Relative)
    }
}

Batch Rename Assets

After finding out what assets are poorly named, I wrote below scripts to batch rename them. As shown by the function name, the three functions have different naming rules.

function Rename-FilesByCreatedTime {
    Get-ChildItem -File | ForEach-Object {
        $creationTime = $_.CreationTime
        $newName = "{0:yy.MM.dd}_{0:HH.mm.ss}{1}" -f $creationTime, $_.Extension
        Rename-Item -Path $_.FullName -NewName $newName
    }
}

function Rename-FilesBySequence {
    Get-ChildItem -File | ForEach-Object {
        $newName = "{0:D2}{1}" -f $count++, $_.Extension
        Rename-Item -Path $_.FullName -NewName $newName
    }
}

function Rename-FilesForUnity {
    Get-ChildItem -File | ForEach-Object {
        $oldName = $_.Name -replace " ", "_"
        $newName = ($oldName -split '_' | ForEach-Object { $_.Substring(0,1).ToUpper() + $_.Substring(1) }) -join '_'
        Rename-Item -Path $_.FullName -NewName $newName
    }
}

Image Processing

Below are scripts that batch process images to make them better fit game engines like Unity, as suggested by the official document.

# Get image information for a list of files.
# Outputs a table with file names, file types, colorspaces, bit depths, and dimensions.
function Get-ImageInfo {
    $imageInfos = @()

    # Use ImageMagick to identify image properties and format the output.
    magick identify -format "%f %m %[colorspace] %z-bit %wx%h`n" * | ForEach-Object {
        $tokens = $_ -split ' '
        $imageInfo = [PSCustomObject]@{
            FileName  = $tokens[0]
            FileType  = $tokens[1]
            Color     = $tokens[2]
            BitDepth  = $tokens[3]
            Dimension = $tokens[4]
        }

        $imageInfos += $imageInfo
    }

    # Sort and display the image information in a table.
    $imageInfos | Sort-Object FileType | Format-Table -AutoSize
}

# Resize images to ensure dimensions are divisible by 4.
# Maintains aspect ratio while resizing.
function Resize-Images4x {
    Get-ChildItem -Include "*.png","*.jpg" -Recurse | ForEach-Object {
    $file = $_.FullName
    
    # Get dimensions of the image.
    $dimensions = $(magick identify -format "%w %h" $file) -split " "
    $width = [int]$dimensions[0]
    $height = [int]$dimensions[1]

    # Initialize new dimensions as old dimensions.
    $new_width = $width
    $new_height = $height

    # Update dimensions only if they are not divisible by 4.
    if ($width % 4 -ne 0) {
        $new_width = [math]::Ceiling($width / 4) * 4
    }
    if ($height % 4 -ne 0) {
        $new_height = [math]::Ceiling($height / 4) * 4
    }

    # Overwrite the original files with resized images.
    magick mogrify -resize "${new_width}x${new_height}!" $file
}
}

# Crop images to a fixed size of 512x512 pixels while maintaining the center of the original image.
function Crop-ImagesTo512x512 {
    Get-ChildItem -Include "*.png","*.jpg","*.webp","*.avif" -Recurse | ForEach-Object {
        magick convert -resize 512x512^ -gravity center -extent 512x512 $_.Name "$($_.BaseName)_512x512$($_.Extension)"
    }
}

# Generate thumbnails for HDR and EXR images in the webp format with specified settings.
function Generate-HDRIThumbnail {
    # Convert HDR and EXR images to webp format with quality and size settings.
    mogrify -format webp -quality 60 -resize 960 -set colorspace RGB -colorspace sRGB *.hdr
    mogrify -format webp -quality 60 -resize 960 -set colorspace RGB -colorspace sRGB *.exr
}

# Optimize PNG images using the oxipng tool with specified options.
function Optimize-PNGImages {
    fd -e png -x oxipng.exe --alpha --zopfli --strip safe
}