Just a little report for anyone who is following my progress on my little 3d painting app from my previous post. I'm trying not to get too carried away spending too long working on this, but am planning to do a release earlier rather than later, even if it has lots of improvements still to be made. I've already got most of the features I was aiming for working, and it can produce some nice results. It is a bit rough around the edges though, and the user interface I need to improve.
As you can see, I've fleshed out the support for layers a bit more. I had to spend a bit of time getting the the scroll bars working properly for the treeview control (as it is my own GUI, I'm continuously finding things that need improving). The layers now support an alpha mask and painting to the alpha mask. So there are actually 2 alpha channels possible per layer, one in the RGBA surface, and one in the mask. This is similar to how photoshop works. So you can draw with e.g. a stippled alpha brush, then later modify which areas are visible using the mask, without affecting the stippling.
One thing I may change is the brush alpha is stored as part of the brush RGBA. You can load the brush alpha mask separately, but as a result of being part of the brush RGBA, the mapping will always be the same as the brush RGB. This is just a compromise, it is slightly less powerful, but it avoids having to worry about 2 sets of brush mappings. I may change my mind though, as it could potentially make brushes look less 'tiley' in some cases.
Aside from the layers, I have developed a 'zone' system, so you can mark out zones of polys to use as masks for drawing. So for instance, you could mask out a shirt, or belt, from the geometry of the model, then be sure that your painting wouldn't extend outside the mask. It is easy to paint the zones in a wireframe mode.
One aspect of the zones I am not happy with is it shows aliasing 'jaggy' artefacts at the side of the polys. This is because a poly is either within the zone, or not. Blender has this same feature for its texture painting and suffers from the same jaggies. However I will probably fix this with some kind of anti-aliasing.
Talking of artefacts, I have totally solved some in a cool way, and noticed a potential problem with the texture filtering. One problem I was having was artefacts on seams in the UV map:
I had a simple solution before, I would simply draw texels with a brush outside a triangle if they were not 'owned' by any triangle. However, I have come up with a better solution, which speeds up determining whether a texel is within a triangle at the same time. I simply precalculate an 'ID map' for the texture, where each texel contains the ID of owner triangle, or 0 if not owned. Then while painting, instead of doing some triangle intersection test, I just check the ID map to see whether the triangle drawing ID matches the ID map for the texel.
To fix the seams issue was quite easy. I do a 'bleedout' algorithm which iteratively moves the triangle IDs outward on the ID map into unused space. So empty space now gets owned by the nearest triangle, and hence drawn into, and artefacts are removed. These would particularly be a problem with mipmapping in a game for example, if they weren't fixed.
The potential problem I have noticed with texture filtering may take a bit more solving. My texture filtering code is rather basic at the moment, and just does a linear interpolate between the 4 nearest texels. This works when the brush scale is around the final texture scale. However, it will look rubbish for minification. So I may have to implement some kind of mipmapping / anisotropic filtering for drawing to the mesh.
Aside from that the biggest change has been, instead of relying on drawing manually to the mesh, I've added a new 'project layer' feature, whereby you can automatically draw to every poly in the model once you have lined up your brush reference image. This is why the alpha mask was necessary. With every poly covered, you then want to be able to show / hide areas on the layer, non-destructively. It works like a charm, and is much easier than manually painting, for the main areas of a model.
The alternative I looked at was 'locking' the mapping of the brush to the mesh once it was lined up, so you could rotate the model but still draw with the same brush mapping. The former approach I used was simpler, and more powerful. The only cost is that it fills the entire layer texture, which means the save files are bigger.
And that brings me finally to loading and saving. I've only just got this working today, as I figured it would be easy. It was quite easy, except I wanted to store save files in a .zip format, so that users could themselves get access to the layers, for editing in photoshop. And keeping a save file in a single zip keeps it self contained and easier to keep track of for the users. It also protects against me accidentally breaking import from earlier versions - the zip file contains .pngs for the layers, so can be used to reconstruct the project, if all else fails.
I am working on the assumption that the .pngs are lossless, and will store RGB information even with zero alpha. I will have to do some testing to check this out .. I suspect it depends on the implementation of the PNG saving code, and the settings. I could alternatively use another format, but no need to reinvent the wheel. Uncompressed save files would be prohibitively huge. I gather TIFF files can store layers, however I know little about them, and they are probably Adobe patented. I generally love PNGs, the only issue I have is that they are rather slow to compress / decompress. Which could be annoying when often saving the project.