<Back

Technical Challenges



Colour compatibility

I wanted to make each hood's colours compatible with every other hood. This was relatively easy as the ordering forms had similar names for parts of the hood. The colours were also easy to change globally. Each image / 3D model shares a few shaders, which affect the colours, so changing a value would update all parts simultaneously. The tricky bit, however, was making the leather colours compatible. I had to make a list of which leather colours are compatible with the neoprene colours and which neoprene colours are compatible with the leather colours. It's not exact, but it's close enough for me.



QOL Colour Selection

A must have quality of life feature for me was being able to right-click on parts of the rendered hood to change the colour. The solution to this stumped me for a while because the buttons that the engine provided only detect a button click in a rectangle. I overcame this by using a low-resolution texture of the hoods and sampling the pixel's colour under the mouse. I used a low-resolution texture so the CPU spends less time looking up the pixel's colour. I would then use the hue of the colour to figure out what part of the image should change colours.

The 3D model viewer uses a similar concept. Initially, I wanted to project a ray from the camera, detect the intersecting face and get the model's UV coordinate but there were no easy solutions for that within the engine. I decided against coding my own solution because I didn't want to bloat my program anymore. Instead, a second hidden viewport renders the 3D models with a different shader that only shows the base colour of the model's texture atlas. This viewport is rendered at a low resolution to not add too much to the draw time and only renders a frame when the mouse clicks. Using the same colour hue lookup method, it figures out which part of the model to change the colour of. I also wanted the user to have the ability to change the mannequin's colour because I realised that not everyone has the same skin colour and might want to see what their hood would look like on them.



Palette Swap

Making a shader that swaps the palette was relatively straightforward. For every texture I encoded the different parts of all of the hoods as different hues. This allowed me to maintain the value and saturation of the image. I wanted to use a shader for the colour change because it would be messy to make images for every part and every colour and layer it all together. My solution also allows me to, in some cases, use only one image where many separate layers would be needed in other methods.



3D Viewer

After finishing the first release of my project, I knew I wanted to add a 3D model viewer. The task was daunting as I knew I would have a fair amount of 3D modelling ahead of me. While I absolutely love 3D modelling, my number one passion, I figured this would be tedious. And it was, especially when it came to optimising the model.

Halfway through modelling for my project, I found a relatively new (as of writing this) website that allows you to customise a K9 hood in 3D www.pups.plus. Upon this discovery, I was discouraged and wondered if it was worth continuing if someone else was already doing a decent job. I pushed on as it was pointed out to me that my program still offered a lot of features that others didn't.

On my first revision of the models, I was disappointed with the resolution of the stitching. I didn't want to increase the texture resolution because I want to conserve as much storage space as possible, so I overlayed as many UVs as possible as they shared similar texture data. This allowed the models to use the texture space more efficiently.



Code Generator

One esspecially challenging task for me was making the hood code generator. I want users to be able to copy the code of their hood and share it with their friends on social media. The recipient would then enter the same code and get the same hood. I realised that due to how many options are presented to the user, the codes could be very long. There are 28 unique settings, and every option combination totals a whopping 1895582315785361442377564160 possible combinations.

I had an insane obsession that the outputted code had to be as short as possible. I didn't want users to share a code 28 characters long, where each character represents a different setting. I eventually came up with a way to multiply and add every setting combination to get a unique integer between 0 and 1895582315785361442377564160. As I've recently discovered, my formula is similar to one that can convert RGB values to a decimal value (if red, green and blue are in the range of 0-255 R^4 + G^2 + B). Fascinatingly, you get a unique number for every possible colour with 8-bit precision.

For my formula, instead of using 255, I use the amount of possible options in each setting. For example, each hood part can be 1 of 28 different colours. One big issue I had with having 1895582315785361442377564160 different combinations is that the engine I'm using stores numbers as 64-bit integers. In most use cases, that is more than enough precision. The 64-bit integer limit is 9223372036854775807, which is far from big enough for me. I had to write my own calculator function that accepts numbers as strings instead because there are different restrictions on strings. Given enough time, the function can solve any simple math equation with huge numbers. It calculates the result similarly to if you had done it by hand without a calculator. There's nothing fancy going on.

You might notice that the code you generate isn't actually an integer between 0 and 1895582315785361442377564160 but instead a short series of numbers letters and symbols. The output code is actually an integer but converted to base 88 to save character space. This means that each digit can represent 88 numbers instead of the familar 10 in base 10. So from 0 to 87 would only be one digit and then 88 onwards would be 2 digits. I initially only wanted to use base 62 because I could use all number and letters (upper case and lower case) but I decided to add all the symbols that can be typed on a standard keyboard as well to further reduce the length of the code.

There are probably better ways to achieve this. I will admitt the functions get a bit slow with extremely large numbers but for my use case, it gets the job done in a reasonable amount of time, and I'm proud of myself for even figuring out how to do it. I taught a computer math lol.